<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022</id>
    <title>Frontend Weekly Blog</title>
    <updated>2022-12-25T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022"/>
    <subtitle>Frontend Weekly Blog</subtitle>
    <icon>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[12月25日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月25日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月25日内容汇总"/>
        <updated>2022-12-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>Dr. Axel 提出两个提案：Iterator Helpers 和 Set Methods — 本篇文章所讲的内容值得你去研究! Dr. Axel 提出了两个具有前瞻性的 ECMAScript 提案，并在本文中介绍了它们，以及解释了为什么它们会对 JavaScript 开发者有用的原因。第一个提案是关于 iterator helpers （用于处理可迭代数据的新的实用方法），第二个提案是关于 Set methods，它扩展了 ES6 的 Set 对象</p><blockquote><p><a href="https://2ality.com/2022/12/iterator-helpers.html" target="_blank" rel="noopener noreferrer">https://2ality.com/2022/12/iterator-helpers.html</a></p></blockquote><p>构建同构 JS 库的五个挑战 — 在 JS 中，同构的意思就是在服务端和浏览器端通过最少的适配使用相同的代码</p><blockquote><p><a href="https://doordash.engineering/2022/12/06/five-challenges-to-building-an-isomorphic-javascript-library/" target="_blank" rel="noopener noreferrer">https://doordash.engineering/2022/12/06/five-challenges-to-building-an-isomorphic-javascript-library/</a></p></blockquote><p>Next, Nest, Nuxt… Nust? — <em>“这篇博客文章是为在寻找新的 JavaScript 后端框架的人准备的。”</em>如果这些框架的名字你分不清，那么这篇文章就是为你准备的。Marius 解释了 Next 和 Gatsby 等系统做了什么，并触及了一些不同之处</p><blockquote><p><a href="https://www.twilio.com/blog/comparing-nextjs-nestjs-nuxt-gatsby" target="_blank" rel="noopener noreferrer">https://www.twilio.com/blog/comparing-nextjs-nestjs-nuxt-gatsby</a></p></blockquote><p>优化 INP 指标，提升用户体验 — 文章仔细介绍了INP指标，如何计算以及如何优化。INP 指标 -—  从用户交互到页面渲染下一帧的时间差，越短越好</p><blockquote><p><a href="https://web.dev/optimize-inp/" target="_blank" rel="noopener noreferrer">https://web.dev/optimize-inp/</a></p></blockquote><p>我们是如何为 Monorepo 项目配置 pnpm 和 Turborepo 的</p><blockquote><p><a href="https://nhost.io/blog/how-we-configured-pnpm-and-turborepo-for-our-monorepo" target="_blank" rel="noopener noreferrer">https://nhost.io/blog/how-we-configured-pnpm-and-turborepo-for-our-monorepo</a></p></blockquote><p>Node 之道：关于设计、架构与最佳实践 — “全图鸟瞰” 式的总结是非常受欢迎的。我们都在为架构设计探索新的设计思路、处理之道。作者在文中总结了在构建高质量 Node 应用程序时，所获得的所有来之不易的最佳实践</p><blockquote><p><a href="https://alexkondov.com/tao-of-node/" target="_blank" rel="noopener noreferrer">https://alexkondov.com/tao-of-node/</a></p></blockquote><p>新选型流行的 Node 开发模式与工具</p><blockquote><p><a href="https://practica.dev/blog/popular-nodejs-pattern-and-tools-to-reconsider/" target="_blank" rel="noopener noreferrer">https://practica.dev/blog/popular-nodejs-pattern-and-tools-to-reconsider/</a></p></blockquote><p>制作现代 npm 包的最佳实践 — 手把手引导如何基于最新的最佳实践创造自己的 npm 包。如果你已经掌握了，也值得再次访问，这是一个很好的、常看常新的资源</p><blockquote><p><a href="https://snyk.io/blog/best-practices-create-modern-npm-package/" target="_blank" rel="noopener noreferrer">https://snyk.io/blog/best-practices-create-modern-npm-package/</a></p></blockquote><p>SWR v2.0: 用于数据获取的 React Hooks — SWR(Stale-While-Revalidate) 的第二个主要版本包括新的 Mutation API、改进的乐观更新 UI 功能、新的开发人员工具以及改进的对并发渲染的支持</p><blockquote><p><a href="https://swr.vercel.app/blog/swr-v2" target="_blank" rel="noopener noreferrer">https://swr.vercel.app/blog/swr-v2</a></p></blockquote><p>避免这些常见的 <code>useState</code> 陷阱 — “你首先需要了解 useState 的潜在问题，以便于避免它们，” 所以 Johannes 带我们用一个案例来深入分析和了解</p><blockquote><p><a href="https://profy.dev/article/react-usestate-pitfalls" target="_blank" rel="noopener noreferrer">https://profy.dev/article/react-usestate-pitfalls</a></p></blockquote><p>Josh W Comeau 更新了他的热门文章 - Why React Re-Renders</p><blockquote><p><a href="https://www.joshwcomeau.com/react/why-react-re-renders/" target="_blank" rel="noopener noreferrer">https://www.joshwcomeau.com/react/why-react-re-renders/</a></p></blockquote><p>用 Three.js 和 react-three-fiber 创建一个 3D 的圣诞体验</p><blockquote><p><a href="https://www.youtube.com/watch?v=tyNt9Qse1mg" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=tyNt9Qse1mg</a></p></blockquote><p>📒 <a href="https://dev.to/aurelievache/learning-go-by-examples-part-7-create-a-cross-platform-gui-desktop-app-in-go-44j1" target="_blank" rel="noopener noreferrer">Learning Go by examples: part 7 - Create a cross-platform GUI/Desktop app in Go</a></p><p>📒 解决 Antd 样式预设影响全局样式问题</p><p>注意 Antd 打包默认会带一套 <code>global.less</code> 样式预设，在某些老工程用的时候，样式预设可能会影响全局样式。由于 Antd 的组件样式都是建立在这个格式化后的样式上的，不引入这个文件则会导致组件内部样式出问题。解决方案是 <strong>收敛 <code>global.less</code>，并保证外部的全局样式无法轻易覆盖 antd 的样式</strong>。</p><p>首先需要限定 <code>global.less</code>，手动套一层作用域：</p><div class="language-less codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">node_modules/antd/lib/style/core/index.less</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-less codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token selector" style="color:#00009f">*[class*='ant-']</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token variable" style="color:#36acaa">@import</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'global.less'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>antd 相关的组件都至少会有一个以 <code>ant-</code> 开头的 class，我们只要利用好这个特点及 CSS 属性选择器即可达到目的</p></blockquote><p>这里存在一个问题，如何将 Antd 的 <code>global.less</code> 文件替换为自己的模块，有两种解决方案：</p><ul><li>用 <code>patch-package</code> 打补丁，但是如果第三方库体积过大会 OOM</li><li>另一种思路是用 <code>NormalModuleReplacementPlugin</code> 在构建阶段去替换模块</li></ul><p>下一步是提升组件样式的权重，此举还能间接提升所有 antd 的样式的权重，避免外部的全局样式对 antd 造成侵入。</p><p>既然是改样式，那就用 CSS 界的 babel —— PostCSS，写个 PostCSS 插件，将所有 <code>.ant</code> 开头的类选择器都同样升高即可。利用的是 <code>postcss-selector-parser</code> 这个 PostCSS 官方提供的解析选择器的库，过滤出「第一个以 <code>ant-</code> 开头的类选择器」，在其前面添加一个属性选择器 <code>[class*='ant-']</code>，如果这个选择器排在当前 rule 的第一个或者前面是一个 combinator，则再加一个通配符 <code>*</code>。</p><p><a href="https://juejin.cn/post/6844904116288749581" target="_blank" rel="noopener noreferrer">如何优雅地彻底解决 antd 全局样式问题</a></p><p>📒 <a href="https://juejin.cn/post/7180242080780779580" target="_blank" rel="noopener noreferrer">对于“前端状态”相关问题，如何思考比较全面</a></p><p>📒 <a href="https://juejin.cn/post/7170852747749621791" target="_blank" rel="noopener noreferrer">二十张图片彻底讲明白Webpack设计理念，以看懂为目的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/be-0gUtcg9o7mAbMnCsYXA" target="_blank" rel="noopener noreferrer">【第2820期】去哪儿网用户体验之端上优化实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/SA2Me6QGkzxLAfhmQ0eWmA" target="_blank" rel="noopener noreferrer">有趣的 Go HttpClient 超时机制</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/dW85gK_5YkwLcj7TxUBHzg" target="_blank" rel="noopener noreferrer">JavaScript 中文周刊 #68 - 如何优化 INP 指标，提升用户体验</a></p><p>📒 <a href="https://juejin.cn/post/7145447742515445791" target="_blank" rel="noopener noreferrer">原生拖拽太拉跨了，纯JS自己手写一个拖拽效果，纵享丝滑</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KLLILNZOlIrrNaKPwORPsA" target="_blank" rel="noopener noreferrer">【综合笔试题】难度 4/5，有一定代码量的图论搜索题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/al5zXILiKnqnsh-XrLMB6A" target="_blank" rel="noopener noreferrer">别乱用了，用新的。Go SliceHeader 和 StringHeader 将会被废弃！</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/T4tk-sckA1oNcWIvp27MMA" target="_blank" rel="noopener noreferrer">看了这篇你会发现，你是懂Go内存分配的</a></p><p>📒 <a href="https://juejin.cn/post/7179049172706787387" target="_blank" rel="noopener noreferrer">你构建的代码为什么这么大</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/vZBePdCuKe12OMQOj6Rz4A" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#24 Not making slice copies correctly</a></p><p>📒 理解 Go generate</p><p><a href="https://go.dev/blog/generate" target="_blank" rel="noopener noreferrer">https://go.dev/blog/generate</a></p><p><a href="https://blog.carlmjohnson.net/post/2016-11-27-how-to-use-go-generate/" target="_blank" rel="noopener noreferrer">https://blog.carlmjohnson.net/post/2016-11-27-how-to-use-go-generate/</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/o8XL71WPDHaui81O61QSoA" target="_blank" rel="noopener noreferrer">专注性能的多端研发框架 - ice.js 3 正式发布！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/p9kHaJQdm3_zi9XlR7VFJg" target="_blank" rel="noopener noreferrer">【综合笔试题】难度 1.5/5，常规二叉树爆搜题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/AMXJpRJ9MU2_jg4utn18eg" target="_blank" rel="noopener noreferrer">低代码没有做到的事情，ChatGPT做到了</a></p><p>⭐️ <a href="https://juejin.cn/post/7093880734246502414" target="_blank" rel="noopener noreferrer">Vue3生命周期Hooks的原理及其与调度器(Scheduler)的关系</a></p><p>📒 开始做请求方案的调研，这是 Umi/Bigfish 今年最佳实践的最后一个拼图。第一个深入看的是 React Query，翻了 Practical React Query | TkDodo's blog 系列文章后做了两篇笔记。然后对 React Query 路转粉，学习到不少关于请求的细节处理思路，推荐大家都好好读一读</p><p><a href="https://tkdodo.eu/blog/practical-react-query" target="_blank" rel="noopener noreferrer">https://tkdodo.eu/blog/practical-react-query</a></p><p>📒 DebugBear 更新了一篇《2022 In Review: What’s New In Web Performance?》 总结 2022 年 Web 性能领域的变化，包括提升资源优先级的 Priority Hints、Chrome 不做 OSCP 证书校验后的性能提升、用于衡量交互后响应速度的 INP 指标、Google 将 Core Web Vitals 纳入排名因素、Chrome 浏览器支持前进后退缓存、HTTP/3 标准化、Chrome DevTool 和 performance API 会提示哪些资源会 block、用于提前提供资源列表的 103 响应、Chrome 108 开始支持全页面预渲染、Safari 支持 AVIF、Safari 原生支持图片懒加载</p><p><a href="https://www.debugbear.com/blog/2022-in-web-performance" target="_blank" rel="noopener noreferrer">https://www.debugbear.com/blog/2022-in-web-performance</a></p><p>📒 StackDiary 更新了《The Most Popular Node.js Frameworks in 2022》和《The Most Popular CSS-in-JS Libraries in 2022》，分别由 Next.js 和 Styled-Components 拔得头筹，Styled-Components 已连续 4 年第一</p><p><a href="https://stackdiary.com/node-js-frameworks/" target="_blank" rel="noopener noreferrer">https://stackdiary.com/node-js-frameworks/</a></p><p><a href="https://stackdiary.com/css-in-js-libraries/" target="_blank" rel="noopener noreferrer">https://stackdiary.com/css-in-js-libraries/</a></p><p>📒 发现一本免费的算法书《Hello 算法》，没细看，感兴趣可关注</p><p><a href="https://www.hello-algo.com/" target="_blank" rel="noopener noreferrer">https://www.hello-algo.com/</a></p><p>📒 React 的 useEvent RFC 里，useEvent 更名为 useEffectEvent，Event function 更名为 Effect Event</p><p><a href="https://github.com/reactjs/reactjs.org/pull/5373" target="_blank" rel="noopener noreferrer">https://github.com/reactjs/reactjs.org/pull/5373</a></p><p>📒 看到 Codux 发布，来自 Wix 联合创始人的作品。这是一个 React 组件可视化编辑器，类似 Storybook，特点是和代码之间双向同步</p><p><a href="https://dev.to/codux/introducing-codux-15j5" target="_blank" rel="noopener noreferrer">https://dev.to/codux/introducing-codux-15j5</a></p><p>📒 React Router 发布 6.5，支持 Optional Route Segments。在任何 path 段末尾添加一个 ? 会使整个路径段成为可选，对静态段和动态参数都有效</p><p><a href="https://github.com/remix-run/react-router/releases/tag/react-router%406.5.0" target="_blank" rel="noopener noreferrer">https://github.com/remix-run/react-router/releases/tag/react-router%406.5.0</a></p><p>📒 Tauri Mobile 发布 Alpha，支持 iOS 和 Andriod，需要用 2.0.0-alpha.0 版本的依赖</p><p><a href="https://tauri.app/blog/2022/12/09/tauri-mobile-alpha/" target="_blank" rel="noopener noreferrer">https://tauri.app/blog/2022/12/09/tauri-mobile-alpha/</a></p><p>📒 <a href="https://www.yuque.com/chencheng/mdh-weekly/gz7aeivrvmfq4p97" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 80 期：SvelteKit 1、Tauri Mobile、RR 6.5、useEffectEvent</a></p><p>📒 <a href="https://juejin.cn/post/7155780555554947102" target="_blank" rel="noopener noreferrer">🌼 细数那些惊艳一时的 CSS 属性</a></p><p>📒 <a href="https://juejin.cn/post/7170278285274775560" target="_blank" rel="noopener noreferrer">关于无感刷新Token，我是这样子做的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bZhumjAQLBETbxrhaO5pCw" target="_blank" rel="noopener noreferrer">JavaScript 中的依赖注入</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/FjbqsQl7g2aSMOhq_ivOhQ" target="_blank" rel="noopener noreferrer">我的Vue.js生态开源之旅</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/YXVURw55G2hT7BtShdGG4A" target="_blank" rel="noopener noreferrer">为什么用公钥加密却不能用公钥解密</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/cZ0fvVmUIrLKwlPFtetPKA" target="_blank" rel="noopener noreferrer">「Go工具箱」一文读懂主流web框架中路由的实现原理</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/H3iygMqDTRWv6h2VcgVeUg" target="_blank" rel="noopener noreferrer">Go类型系统：有何与众不同</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[12月18日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月18日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月18日内容汇总"/>
        <updated>2022-12-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>何时使用 gRPC 与 GraphQL - 本篇文章比较了两个流行的 API 协议，以了解每个协议在哪些方面最有效</p><blockquote><p><a href="https://stackoverflow.blog/2022/11/28/when-to-use-grpc-vs-graphql/" target="_blank" rel="noopener noreferrer">https://stackoverflow.blog/2022/11/28/when-to-use-grpc-vs-graphql/</a></p></blockquote><p>关于使用 Rust 优化 JavaScript 的讨论 — 在最近的 Next.js 会议上与 Vercel 的 Lee Robinson 交谈</p><blockquote><p><a href="https://stackoverflow.blog/2022/12/09/ready-to-optimize-your-javascript-with-rust/" target="_blank" rel="noopener noreferrer">https://stackoverflow.blog/2022/12/09/ready-to-optimize-your-javascript-with-rust/</a></p></blockquote><p>用于安全发布和安全消费的新 npm 功能 — GitHub 正在继续努力使 npm 生态系统更加安全。这篇文章介绍了两个新东西：细粒度访问令牌 用于帮助包所有者控制对发布工作流程的访问，以及一个新的 代码浏览器，可以直接查看来自官方 npm 站点的包的内容</p><blockquote><p><a href="https://github.blog/2022-12-06-new-npm-features-for-secure-publishing-and-safe-consumption/" target="_blank" rel="noopener noreferrer">https://github.blog/2022-12-06-new-npm-features-for-secure-publishing-and-safe-consumption/</a></p></blockquote><p>在 2023 年使用 TypeScript 设置 Node.js — 这是一本方便、制作精良的入门读物，可以帮助你在短短四分钟内掌握使用 TypeScript 和 Node 的基本知识。</p><blockquote><p><a href="https://www.youtube.com/watch?v=H91aqUHn8sE" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=H91aqUHn8sE</a></p></blockquote><p>40+ Node.js 集成测试最佳实践 — 组件/集成测试正在成为越来越受欢迎的后端测试技术。这个仓库深入研究了各种快速模式和实践，以创建良好的组件测试。同时，还有一个演示应用程序和使用 Jest、Mocha、Express、Fastify 和 Nest.js 的示例</p><blockquote><p><a href="https://github.com/testjavascript/nodejs-integration-tests-best-practices" target="_blank" rel="noopener noreferrer">https://github.com/testjavascript/nodejs-integration-tests-best-practices</a></p></blockquote><p>“停止编写虚假的 React 代码” — Jack 不喜欢在 React 应用中使用普通的 JavaScript，因为惯用的 React 风格的方法会让人感觉更自然。他分享了一些避免自己陷入同样问题的规则</p><blockquote><p><a href="https://www.youtube.com/watch?v=s-lumOeD2fk" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=s-lumOeD2fk</a></p></blockquote><p>Storybook 团队已经分享了对包括 Next.js、SvelteKit 和 Remix 在内的框架的 未来支持的更新。其中大部分将于 2023 年到来</p><blockquote><p><a href="https://storybook.js.org/blog/framework-api/" target="_blank" rel="noopener noreferrer">https://storybook.js.org/blog/framework-api/</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/2Rwy19C0eUshTWc_JfTPig" target="_blank" rel="noopener noreferrer">Redis分布式锁的10个坑</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QQjOyYkDfuxIxHl6k6qkRA" target="_blank" rel="noopener noreferrer">一文彻底理解Go语言栈内存/堆内存</a></p><p>📒 <a href="https://juejin.cn/post/7169004126469914654" target="_blank" rel="noopener noreferrer">Rollup 与 Webpack 的 Tree-shaking</a></p><p>📒 <a href="https://juejin.cn/post/7021115814870810660" target="_blank" rel="noopener noreferrer">Rollup源码：模块打包与Tree-Shaking</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/19Ai1rbRoQxOBA5SXSNCAQ" target="_blank" rel="noopener noreferrer">Vite 特性和部分源码解析</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/TvLWXX4bpVYOalywiupvFQ" target="_blank" rel="noopener noreferrer">【第2814期】如何更新 NPM 依赖</a></p><p>📒 <a href="https://juejin.cn/post/7176963906844246074" target="_blank" rel="noopener noreferrer">Webpack深度进阶：两张图彻底讲明白热更新原理！</a></p><p>📒 <a href="https://juejin.cn/post/7170852747749621791" target="_blank" rel="noopener noreferrer">二十张图片彻底讲明白Webpack设计理念，以看懂为目的</a></p><p>📒 <a href="https://juejin.cn/post/7182462103297458236" target="_blank" rel="noopener noreferrer">谈谈复杂应用的状态管理（下）：基于 Zustand 的渐进式状态管理实践</a></p><p>📒 <a href="https://juejin.cn/post/7177216308843380797" target="_blank" rel="noopener noreferrer">谈谈复杂应用的状态管理（上）：为什么是 Zustand</a></p><p>📒 <a href="https://juejin.cn/post/7177585131861835837" target="_blank" rel="noopener noreferrer">React Native工程Monorepo改造实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JzHA3htAjHXhQ4HeshflzA" target="_blank" rel="noopener noreferrer">【第2813期】网易严选APP端上H5容器化建设</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/setWdt_6S26_-tEX7ua07g" target="_blank" rel="noopener noreferrer">Go 1.20 新特性之 time.Compare</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/x_Z58gxrzhJURRhIdxfpEg" target="_blank" rel="noopener noreferrer">【综合笔试题】难度 3.5/5，括号相关剪枝搜索题</a></p><p>📒 <a href="https://juejin.cn/post/7176943264749060155" target="_blank" rel="noopener noreferrer">Umi 中如何根据服务端响应数据动态更新路由</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/svGYB3HvmLDMerlM50BhAg" target="_blank" rel="noopener noreferrer">深度解析 React 性能优化 API</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/rtEhjJhwdkX3U01vHG6S8g" target="_blank" rel="noopener noreferrer">Go1.20 将会修改全局变量的初始化顺序。梅度二开，继续打破 Go1 兼容性承诺！</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/LW8Woq5Rg4x31DbtD-_jeA" target="_blank" rel="noopener noreferrer">两种 Option 编程模式的实现，Uber推荐这一种</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/oO-WpgdszWrBxOOxSFWFRw" target="_blank" rel="noopener noreferrer">哔哩哔哩 Web 首页重构——回首2021</a></p><p>📒 <a href="https://juejin.cn/post/7176430181765087269" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 63 期：Vite 4.0、State of CSS 2022、Rome v11、Web 性能日历、VueConf 2022 PPT</a></p><p>📒 <a href="https://juejin.cn/post/7176504540793929789" target="_blank" rel="noopener noreferrer">【综合笔试题】难度 3/5，多解法热门搜索题</a></p><p>📒 <a href="https://juejin.cn/post/7176275850101260325" target="_blank" rel="noopener noreferrer">ChatGPT 以及相关开源项目体验</a></p><p>📒 Webpack 构建流程</p><p><a href="https://segmentfault.com/a/1190000012081469" target="_blank" rel="noopener noreferrer">玩转webpack（一）上篇：webpack的基本架构和构建流程</a></p><p><a href="https://segmentfault.com/a/1190000012099163" target="_blank" rel="noopener noreferrer">玩转webpack（一）下篇：webpack的基本架构和构建流程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hqTB22O0SXfMSBrEuvTvjg" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 79 期：ChatGPT、Vite 4、SWR 2、Intl.Segmenter</a></p><p>📒 <a href="https://gocn.github.io/styleguide/docs/02-guide/" target="_blank" rel="noopener noreferrer">Google Go 编程规范</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/SFbSAGwQgQBVWpySYF-rkw" target="_blank" rel="noopener noreferrer">Go版本大于1.13，程序里这样做错误处理才地道</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6dsPnQlq8BfHkdibfiNcUg" target="_blank" rel="noopener noreferrer">【第2809期】大型会场活动线上保障方案</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/5aScdlfyWM25VoekLlHhVQ" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 171 期</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[12月11日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月11日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月11日内容汇总"/>
        <updated>2022-12-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>Storybook 发布了 一个新的 API。本次更新旨在使对 Vite、Next.js、Svelte、Remix 和 Nuxt 等的支持在 2023 年更容易发布。"对任何框架的零配置支持"。</p><blockquote><p><a href="https://storybook.js.org/blog/framework-api/" target="_blank" rel="noopener noreferrer">https://storybook.js.org/blog/framework-api/</a></p></blockquote><p>入门 Zustand — 本文给出了几个使用 Zustand 的技巧。Zustand 是一个相对最小的状态管理库，拥有很多热情的用户</p><blockquote><p><a href="https://tkdodo.eu/blog/working-with-zustand" target="_blank" rel="noopener noreferrer">https://tkdodo.eu/blog/working-with-zustand</a></p></blockquote><p>Shopify 衡量 React Native 渲染时间的解决方案 — 阅读本文可以了解更多关于 Shopify 的开源库 react-native-performance 是如何工作的，用户如何使用该库，以及为什么测量性能如此重要</p><blockquote><p><a href="https://shopify.engineering/measuring-react-native-rendering-times" target="_blank" rel="noopener noreferrer">https://shopify.engineering/measuring-react-native-rendering-times</a></p></blockquote><p>给 React 开发者的一篇 CSS 变量教程 — 这是一篇新推出的文章，对如何在项目中使用 CSS 变量（自定义属性）进行了深入的研究</p><blockquote><p><a href="https://www.joshwcomeau.com/css/css-variables-for-react-devs/" target="_blank" rel="noopener noreferrer">https://www.joshwcomeau.com/css/css-variables-for-react-devs/</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7175444694917185591" target="_blank" rel="noopener noreferrer">【VueConf 2022】尤雨溪：Vue的进化历程</a></p><p>📒 Nodejs 的 stream 操作</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> Readable </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node:stream"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> fs </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node:fs"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> readable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Readable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">readable</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"测试内容"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">readable</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// no more data</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 将可读流复制到标准输出</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">readable</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">stdout</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 将可读流复制到文件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> writable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">createWriteStream</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/xxx"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">readable</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">pipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">writable</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://zhuanlan.zhihu.com/p/36728655" target="_blank" rel="noopener noreferrer">Node.js 流（stream）：你需要知道的一切</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/0zDIPKUqPslj1EvowDXigA" target="_blank" rel="noopener noreferrer">Vite 4.0 正式发布！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1d4XUoW5e45jYeEJEWoXeQ" target="_blank" rel="noopener noreferrer">Go1.20 将禁止匿名接口循环导入！这是一次打破 Go1 兼容性承诺的真实案例</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/8JwAlMU6DUWTxzFYKxTH3A" target="_blank" rel="noopener noreferrer">【第2806期】从Lint工具窥探前端的clean-code</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/w5guASrl7G6yl09HkPd5LQ" target="_blank" rel="noopener noreferrer">Go1.20 继续优化 errors 库</a></p><p>📒 <a href="https://juejin.cn/post/7145703734230646792" target="_blank" rel="noopener noreferrer">《MiniReact》带你循环渐进了解React原理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/iemuo3gR4yU17ymSwTnoGQ" target="_blank" rel="noopener noreferrer">从0.5到1用golang上线一个web项目</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/abxUanLzPnU8PxFqN6IjjQ" target="_blank" rel="noopener noreferrer">从0到0.5用golang写一个web项目</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Q9VNdOXGlsA4OXRUc5_-xw" target="_blank" rel="noopener noreferrer">我们是如何追逐元宇宙、XR等“概念股”浪潮的</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/UQwOJVqm5gnQPMgSE3MW9w" target="_blank" rel="noopener noreferrer">[<!-- -->译<!-- -->]<!-- -->Uber 的 Go语言开发规范</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/vufI24NCasCT32UQG3A_UQ" target="_blank" rel="noopener noreferrer">【第2805期】React 数据获取与性能优化</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6UPhAlu-IklPW3SKJCEurA" target="_blank" rel="noopener noreferrer">就在刚刚 Go 1.20 rc 1 发布啦!</a></p><p>📒 CSS 小技巧</p><p><code>background</code> 有哪些属性：</p><ul><li><code>background-color</code></li><li><code>background-image</code></li><li><code>background-position</code></li><li><code>background-size</code></li><li><code>background-repeat</code></li></ul><p>常见用法：</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">background-image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token url function" style="color:#d73a49">url</span><span class="token url punctuation" style="color:#393A34">(</span><span class="token url" style="color:#36acaa">xxx</span><span class="token url punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/** 背景图片填充，适配短边，两个属性通常一起用 */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">background-size</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> contain</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">background-repeat</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> no-repeat</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/** 背景图片填充，适配长边 */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">background-size</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> contain</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/** 自定义背景图片大小，同时自定义布局 */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">background-size</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">58</span><span class="token unit">px</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">48</span><span class="token unit">px</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">background-position</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> top </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> left </span><span class="token number" style="color:#36acaa">6</span><span class="token unit">px</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>transition</code> 动画可以配合 <code>will-change</code> 属性一起用：</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">background</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color">transparent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">will-change</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> background</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">transition</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> background </span><span class="token number" style="color:#36acaa">0.3</span><span class="token unit">s</span><span class="token plain"> ease</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/GVts2QW3H_aTrB9anGwl5g" target="_blank" rel="noopener noreferrer">React Streaming SSR 原理解析</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/yKm_U9Veh_1twIoXzM8Prw" target="_blank" rel="noopener noreferrer">Nest.js进阶系列四：Node.js中使用Redis原来这么简单！</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/TmCtsbhjexZNCdvUSXdNCw" target="_blank" rel="noopener noreferrer">Redis学习-入门篇</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/c9i2dhBf6P_zrhGF2FUpzA" target="_blank" rel="noopener noreferrer">【面试高频题】难度 2/5，回溯算法经典运用</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hLDtOz2AEbLCdRVBHkb3MQ" target="_blank" rel="noopener noreferrer">【第2804期】Islands 架构原理和实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XzI4eXkj2xH_XxRAt2QISw" target="_blank" rel="noopener noreferrer">Go 1.19.4 和 Go 1.18.9 发布安全更新，涉及 os http 以及 http2 header 缓存等问题</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/29xlEK2N_Wptl4TBMg1ZPQ" target="_blank" rel="noopener noreferrer">源码深度解析之 Spring IOC</a></p><p>📒 <a href="https://juejin.cn/post/7174027619984867341" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 62 期：11 月登陆浏览器的新特性、VueConf 2022、第 93 次 TC39 会议、TS 挑战</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/SG9sNmMu9acB1xTODkG00Q" target="_blank" rel="noopener noreferrer">还在用HttpUtil？SpringBoot 3.0全新HTTP客户端工具来了，用起来够优雅！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yvDkQUQtI-6BvlylC1Q7Ig" target="_blank" rel="noopener noreferrer">历时8个月，10w字！前端知识体系+大厂面试总结（基础知识篇）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zCh12E10JM24EGTyFS7hPQ" target="_blank" rel="noopener noreferrer">你也是业务开发？提前用这个设计模式预防产品加需求吧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JDquIbunGuFHIgo2Clp3iw" target="_blank" rel="noopener noreferrer">美团二面：TCP 四次挥手，可以变成三次吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/gfUM4EjE1av_YBeUBFyKtA" target="_blank" rel="noopener noreferrer">Go1.20 继续小修小补 errors 库</a></p><p>📒 MDH 前端周刊第 78 期：技术文档框架、CSS Architecture、Tailwind 抽象泄漏、调试战术</p><p>原文链接：</p><blockquote><p><a href="https://www.yuque.com/chencheng/mdh-weekly/hdwfxidpn4u2bboo" target="_blank" rel="noopener noreferrer">https://www.yuque.com/chencheng/mdh-weekly/hdwfxidpn4u2bboo</a></p></blockquote><p><a href="https://mp.weixin.qq.com/s/iPbUVSWIyfz1o1aISua9sg" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 78 期：技术文档框架、CSS Architecture、Tailwind 抽象泄漏、调试战术</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ZUe4t589ECmYpipph38nuw" target="_blank" rel="noopener noreferrer">【面试高频题】难度 3/5，状态压缩 DP 及其优化</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/IelVDnMzGtT5y7hGSb_OxA" target="_blank" rel="noopener noreferrer">面试官：net/http库知道吗？能说说优缺点吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/WsFGv9tcdRLP9K-NQSqimA" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#23 Not properly checking if a slice is empty</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/AR4schTcEkc0lOObZA-jRQ" target="_blank" rel="noopener noreferrer">【第2802期】Islands Architecture（孤岛架构）在携程新版首页的实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/rOtR8FfMpfBZrIkyRrNsfQ" target="_blank" rel="noopener noreferrer">Go 语言代码风格规范-指南篇</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pXqtEiRWt1nou7T2AueHtw" target="_blank" rel="noopener noreferrer">Redis 7.0 源码调试环境搭建与源码导读技巧</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[12月4日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月4日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/12月4日内容汇总"/>
        <updated>2022-12-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>Ant Design v5.0: 企业级设计语言 React UI 组件库 — Ant Design 5.0 版本提供了更多的组件，简约的设计以及更强的动态主题和定制主题。这里有面向老用户的升级指南：从 v4 到 v5 – 官方首页。</p><blockquote><p><a href="https://github.com/ant-design/ant-design/issues/38671" target="_blank" rel="noopener noreferrer">https://github.com/ant-design/ant-design/issues/38671</a></p></blockquote><p>如何优化 Vue.js 应用程序 — 涵盖了构建 Vue 应用程序时要牢记的一些基本思想。</p><blockquote><p><a href="https://www.smashingmagazine.com/2022/11/optimizing-vue-app/" target="_blank" rel="noopener noreferrer">https://www.smashingmagazine.com/2022/11/optimizing-vue-app/</a></p></blockquote><p>以正确的方式编写和组织 Node API 测试</p><blockquote><p><a href="https://larswaechter.dev/blog/nodejs-api-testing/" target="_blank" rel="noopener noreferrer">https://larswaechter.dev/blog/nodejs-api-testing/</a></p></blockquote><p>使用 TypeScript 生成原生的 ESM</p><blockquote><p><a href="https://2ality.com/2021/06/typescript-esm-nodejs.html" target="_blank" rel="noopener noreferrer">https://2ality.com/2021/06/typescript-esm-nodejs.html</a></p></blockquote><p>需要避免的 Node.js 架构陷阱</p><blockquote><p><a href="https://blog.appsignal.com/2022/11/23/nodejs-architecture-pitfalls-to-avoid.html" target="_blank" rel="noopener noreferrer">https://blog.appsignal.com/2022/11/23/nodejs-architecture-pitfalls-to-avoid.html</a></p></blockquote><p>Hyperstack：一个受 Rails 启发的新的 Node.js Web 框架</p><blockquote><p><a href="https://hyperstackjs.io/" target="_blank" rel="noopener noreferrer">https://hyperstackjs.io/</a></p></blockquote><p>将 React 交互时间缩短 4 倍</p><blockquote><p><a href="https://www.causal.app/blog/react-perf" target="_blank" rel="noopener noreferrer">https://www.causal.app/blog/react-perf</a></p></blockquote><p>在 Deno 中使用框架构建应用程序.. 比如 Reac</p><blockquote><p><a href="https://deno.com/blog/frameworks-with-npm" target="_blank" rel="noopener noreferrer">https://deno.com/blog/frameworks-with-npm</a></p></blockquote><p>在 React 应用中使用几种数据结构的真实案例</p><blockquote><p><a href="https://profy.dev/article/javascript-data-structures" target="_blank" rel="noopener noreferrer">https://profy.dev/article/javascript-data-structures</a></p></blockquote><p>Clapy：一款 Figma 插件，可基于 Figma 设计产出 React 组件</p><blockquote><p><a href="https://clapy.co/" target="_blank" rel="noopener noreferrer">https://clapy.co/</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/IvL24_7iuuRp9Y3dljHaHQ" target="_blank" rel="noopener noreferrer">GoLand 迎来五周年，同时发布 2022.3：有彩蛋</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/UetEZPco-dKDSwrtchVT7g" target="_blank" rel="noopener noreferrer">了解微前端，深入前端架构的前世今生</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/NPTNbn4C6Rbn6gQLyxWzsg" target="_blank" rel="noopener noreferrer">CSS 方案 2022</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/Ebh5iVsx0iExb5Wxq3tQFQ" target="_blank" rel="noopener noreferrer">公司新来一个同事，把优惠券系统设计的炉火纯青！</a></p><p>⭐️ <a href="https://juejin.cn/post/7172001951784108040" target="_blank" rel="noopener noreferrer">傻瓜方式分析前端应用的体积</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/uHmCU0v0xJ2RYlmq_lQAiQ" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#22 Being confused about nil vs. empty slices</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/xcQIvH4N11VtUHcA3SmSfA" target="_blank" rel="noopener noreferrer">18.6K Star！这款 JSON 数据可视化工具太优雅了！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/vB9ElJCfgZeQHtB596XHpA" target="_blank" rel="noopener noreferrer">Go 服务自动收集线上问题现场</a></p><p>📒 <a href="https://juejin.cn/post/6998785406619615269" target="_blank" rel="noopener noreferrer">TypeScript从平凡到不凡（基础篇）</a></p><p>⭐️ <a href="https://juejin.cn/post/6858905382861946894" target="_blank" rel="noopener noreferrer">Webpack配置全解析（优化篇）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/uMMWVYDWtLKbQtI1LSzRVg" target="_blank" rel="noopener noreferrer">用 Wireshark 让你看见 TCP 到底是什么样！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/44yqylI6_Za6sBUiwlLMXA" target="_blank" rel="noopener noreferrer">大象在云端起舞：后 Hadoop 时代的字节跳动云原生计算平台——云原生计算团队采访</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XSIjKlUyFpcq9BkwXsjR6g" target="_blank" rel="noopener noreferrer">【面试高频题】难度 3/5，设计跳表（数据结构经典考察）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JL9zUDMb1Y4BRUnBzyZPsw" target="_blank" rel="noopener noreferrer">动图图解 | UDP就一定比TCP快吗</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/i1N9bmVSW1lGfOezvhcD7g" target="_blank" rel="noopener noreferrer">深入理解 golang 的互斥锁</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QtFkh5d7Y-n2i4JI6tUaNA" target="_blank" rel="noopener noreferrer">说两个 Go 循环里的坑，第二个在JS里也有</a></p><p>📒 <a href="https://juejin.cn/post/7171366091459919879" target="_blank" rel="noopener noreferrer">React Server Component: 混合式渲染</a></p><p>📒 <a href="https://juejin.cn/post/7170288636921905183" target="_blank" rel="noopener noreferrer">前端工程化基建探索（5）Vite4.0.0都悄悄在“卷”出来了，是时候去探索Vite的设计和实现了</a></p><p>📒 <a href="https://juejin.cn/post/7166921765317738503" target="_blank" rel="noopener noreferrer">前端工程化基建探索（4）从源码出发探索理解webpack核心特性</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JoVO3ZpuhqZ2xq15Q0NkJA" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 61 期：State of JavaScript、Prettier 2.8、Flexbox 交互式指南</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mQ2xQi9K1d6idAAsQSw0Mw" target="_blank" rel="noopener noreferrer">彻底搞懂 React 18 并发机制的原理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yibdTovg4-7LwEhdDiywqw" target="_blank" rel="noopener noreferrer">读完《重构》我学到了这些提升代码质量的编程技巧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cOj3DzUj6_CTEH8IjK6nMA" target="_blank" rel="noopener noreferrer">一款好用的 Go 调用链可视化工具</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cZWUOroRfHHE_8fuGxQfLA" target="_blank" rel="noopener noreferrer">用Go学设计模式- 模板模式</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mFmZD98KPsNk9JHm3wq2og" target="_blank" rel="noopener noreferrer">Go Context 怎么用，原理是啥，看完这篇就清晰了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3uWozu4VIUJHyIGut3_0Bg" target="_blank" rel="noopener noreferrer">Go 模糊测试fuzzing的原理分析</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Sp2hlxUcY45-v9nlIhEOow" target="_blank" rel="noopener noreferrer">为iframe正名，你可能并不需要微前端</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/MOzCzq8DUEIKtJ3lMu4s2g" target="_blank" rel="noopener noreferrer">现代CSS样式重置最佳实践！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/M2-XXPdLKlTqzGefz7UPvA" target="_blank" rel="noopener noreferrer">如何解决前端领域的竞态问题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1xY0hfcwJci1hr4TKUZMqg" target="_blank" rel="noopener noreferrer">【第2795期】雪球跨端架构建设之三端同构篇</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/7WU1DDoMYQzXnlstz16QJA" target="_blank" rel="noopener noreferrer">【第2785期】雪球跨端架构建设之跨端容器篇</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/RCBUlu0gRuVFSQ2m8Uyycg" target="_blank" rel="noopener noreferrer">Go 语言代码风格规范-概述篇</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3FONsVCFYNvaz1yW1EVgxg" target="_blank" rel="noopener noreferrer">DNS中有哪些值得学习的优秀设计</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yg3jgq85MQNzm_UqTyZ7pQ" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 169 期 — 正确率 23%</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[11月27日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月27日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月27日内容汇总"/>
        <updated>2022-11-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>重构 React 代码：减少 43% 代码并且数据结构更加清晰</p><blockquote><p><a href="https://profy.dev/article/react-junior-code-review-and-refactoring-1" target="_blank" rel="noopener noreferrer">https://profy.dev/article/react-junior-code-review-and-refactoring-1</a></p></blockquote><p>使用 TypeScript 编写 React 组件</p><blockquote><p><a href="https://www.robinwieruch.de/typescript-react-component/" target="_blank" rel="noopener noreferrer">https://www.robinwieruch.de/typescript-react-component/</a></p></blockquote><p>What and Why：Next.js 13 中的 React Server Components</p><blockquote><p><a href="https://thetombomb.com/posts/react-server-components-nextjs" target="_blank" rel="noopener noreferrer">https://thetombomb.com/posts/react-server-components-nextjs</a></p></blockquote><p>Twix: 使用 Tailwind CSS 实现 React 组件样式</p><blockquote><p><a href="https://github.com/Idered/twix" target="_blank" rel="noopener noreferrer">https://github.com/Idered/twix</a></p></blockquote><p>Deno v1.28 发布：现在有 130 万个新模块。Deno 现在正式支持以“稳定”的方式使用 npm 模块，并且不需要涉及 <code>node_modules</code>、<code>package.json</code> 或 <code>npm install</code> 这些出现在 Node 中的内容</p><blockquote><p><a href="https://deno.com/blog/v1.28" target="_blank" rel="noopener noreferrer">https://deno.com/blog/v1.28</a></p></blockquote><blockquote><p><a href="https://www.youtube.com/watch?v=X2qxpDriWjY" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=X2qxpDriWjY</a></p></blockquote><p>Wireit：升级 npm 脚本，使它们更智能、更高效</p><blockquote><p><a href="https://github.com/google/wireit" target="_blank" rel="noopener noreferrer">https://github.com/google/wireit</a></p></blockquote><p>使用 WebAssembly 增强 Node.js</p><blockquote><p><a href="https://www.youtube.com/watch?v=bYCrCKNJBW8" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=bYCrCKNJBW8</a></p></blockquote><p>函数式编程到底有什么优点 — 本篇文章是由即将出版的 《Skeptic’s Guide to Functional Programming with JavaScript》的作者 James 以一种更容易理解的方式书写的函数式编程思想的文章，相信你读完本篇文章会大有收获</p><blockquote><p><a href="https://jrsinclair.com/articles/2022/whats-so-great-about-functional-programming-anyway/" target="_blank" rel="noopener noreferrer">https://jrsinclair.com/articles/2022/whats-so-great-about-functional-programming-anyway/</a></p></blockquote><p>用 Storyboook 和 Nightwatch 实践组件驱动开发</p><blockquote><p><a href="https://pineview.io/supercharge-your-storybook-with-nightwatch-testing/" target="_blank" rel="noopener noreferrer">https://pineview.io/supercharge-your-storybook-with-nightwatch-testing/</a></p></blockquote><p>tslog v4.0：支持 JS、TS 的日志输出库— 功能丰富，类型齐全，可以通过本机 V8 进行堆栈跟踪 API、显示代码框架等。现在支持 Node 和浏览器</p><blockquote><p><a href="https://tslog.js.org/" target="_blank" rel="noopener noreferrer">https://tslog.js.org/</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/2My8UeAgH9PXRJ5iDAkQJA" target="_blank" rel="noopener noreferrer">开源低代码表单方案 Formily 的核心设计思路</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/OSqCRM3gU9QfAVJOaQyS-Q" target="_blank" rel="noopener noreferrer">微前端场景下的代码共享</a></p><p>📒 相关文章推荐</p><p><a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe" target="_blank" rel="noopener noreferrer">How to Create and Publish a React Component Library</a></p><p><a href="https://dev.to/alexeagleson/how-to-build-a-rust-cli-tool-to-generate-typescript-types-from-rust-20cm" target="_blank" rel="noopener noreferrer">How to Build a Rust CLI Tool to Generate Typescript Types from Rust</a></p><p><a href="https://medium.com/a-layman/build-micro-frontends-in-nextjs-and-reactjs-with-webpack-5-module-federation-e142ad76f48c" target="_blank" rel="noopener noreferrer">Build Micro frontends in NextJS and ReactJS with Webpack 5 Module Federation</a></p><p><a href="https://dev.to/omher/building-react-app-with-module-federation-and-nextjsreact-1pkh" target="_blank" rel="noopener noreferrer">Building React App with Module Federation and NextJS/React</a></p><p>📒 Next.js 相关内容</p><p><a href="https://juejin.cn/post/7168885699507126303" target="_blank" rel="noopener noreferrer">使用 Next.js 搭建 Monorepo 组件库文档</a></p><p><a href="https://juejin.cn/post/7162775935828115469" target="_blank" rel="noopener noreferrer">理解 Next.js 中的 CSR、SSR、SSG、ISR 以及 Streaming</a></p><p>Next.js 13 新增特性：</p><ul><li><p>启用实验性 <code>app</code> 目录实现约定式路由，路由每个片段必须要有一个目录承载，内部包含一个 <code>page.tsx</code> 作为主页面，还可以包含 <code>layout.tsx</code> 作为该路由的公共导航，切换路由时，不会刷新</p></li><li><p><code>app</code> 目录下的组件默认启用 Server Component（当然也可用于 SSG 渲染），与传统的 SSR 不同，优点是拥有 <strong>流式 HTML 和选择性注水</strong></p></li><li><p>React Suspense API 解锁了 React 18 中的两个主要 SSR 功能：</p><ul><li>在服务器上流式传输 HTML
要实现这个功能，需要从原来的方法切换 <code>renderToString</code> 切换到新 <code>renderToPipeableStream</code> 方法</li><li>客户端的选择性注水作用
使用 <code>hydrateRoot</code> 代替 <code>createRoot</code> 方法</li></ul></li><li><p>区分服务端组件和客户端组件</p><ul><li>Next.js 12 在 <code>useEffect</code>、 <code>onChange</code> 等回调函数可以在客户端执行（一般针对浏览器和 Node API 判断）</li><li>在 Next13 中 ， 在 <code>app</code> 目录下由于启用了 Server Component，无法使用 client-only 特性（例如 <code>useState</code>、<code>useEffect </code>、<code>createContext</code>），因此判断环境非常重要。如要使用 <code>useState</code> 等状态管理的 hook，那么该组件只在客户端执行，需要在首行加入 <code>'use client'</code> 指令</li></ul></li><li><p>数据请求。Next.js 13 的 <code>app</code> 目录不再需要 <code>getStaticProps</code>、<code>getServerSideProps</code>，而是默认启用了 Static Rendering（相当于 SSG），如果需要切换渲染模式，只需要修改 <code>fetch</code> 的缓存策略：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'https://...'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 默认 'force-cache'，相当于 `getStaticProps`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'https://...'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> next</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> revalidate</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 请求被缓存 10s，相当于 `getStaticProps` 加上 `revalidate` 参数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'https://...'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> cache</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'no-store'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 每次刷新都会重新请求，相当于 `getServerSideProps`</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>获取数据之后可以直接用 <code>use()</code> 在服务端消费，渲染 UI。注意 <code>app</code> 目录下的 Server Component 不能用 <code>useState</code>（虽然可以加上 <code>'use client'</code> 改为客户端组件），Next.js 13 建议都在服务端调接口获取数据</p></blockquote></li><li><p>此外在 SSG 渲染中常用的 <code>getStaticPaths</code> 改为了 <code>generateStaticParams</code></p></li></ul><p>参考：</p><p><a href="https://beta.nextjs.org/docs/rendering/server-and-client-components#when-to-use-server-vs-client-components" target="_blank" rel="noopener noreferrer">https://beta.nextjs.org/docs/rendering/server-and-client-components#when-to-use-server-vs-client-components</a></p><p><a href="https://beta.nextjs.org/docs/rendering/static-and-dynamic-rendering" target="_blank" rel="noopener noreferrer">https://beta.nextjs.org/docs/rendering/static-and-dynamic-rendering</a></p><p><a href="https://beta.nextjs.org/docs/data-fetching/fetching" target="_blank" rel="noopener noreferrer">https://beta.nextjs.org/docs/data-fetching/fetching</a></p><p><a href="https://beta.nextjs.org/docs/upgrade-guide#dynamic-paths-getstaticpaths" target="_blank" rel="noopener noreferrer">https://beta.nextjs.org/docs/upgrade-guide#dynamic-paths-getstaticpaths</a></p><p>一个 Next.js 13 的演示教程，里面讲了一个 use 导致的无限循环 bug</p><blockquote><p><a href="https://www.youtube.com/watch?v=zwQs4wXr9Bg" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=zwQs4wXr9Bg</a></p></blockquote><p><a href="https://juejin.cn/post/7160084572942630926#heading-13" target="_blank" rel="noopener noreferrer">你好，Next.js 13</a></p><p>📒 React-query 相关文章</p><p><a href="https://juejin.cn/post/7169515109172609032" target="_blank" rel="noopener noreferrer">React Query 原理与设计</a></p><p><a href="https://juejin.cn/post/6930542093840416776" target="_blank" rel="noopener noreferrer">用react-query解决你一半的状态管理问题</a></p><p>📒 <a href="https://juejin.cn/post/7157594175846744071" target="_blank" rel="noopener noreferrer">适合团队和个人项目的 Golang 编码规范</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/CctmY6NS2zQY8d7l7O2dpg" target="_blank" rel="noopener noreferrer">优化 CSS 代码的12个小技巧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3yHSh7djpeeYZkajkTGFKg" target="_blank" rel="noopener noreferrer">推荐一款SQL自动检查神器，再也不用担心SQL出错了！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2tcAHWQTI75UjBZLieY7FQ" target="_blank" rel="noopener noreferrer">【第2791期】可扩展 CSS 的演变</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/UEzprqAEeTrdJt1NxTT49A" target="_blank" rel="noopener noreferrer">接口502了，运维和研发谁的锅</a></p><p>📒 <a href="https://juejin.cn/post/7168835045984043022" target="_blank" rel="noopener noreferrer">Element Plus 组件库相关技术揭秘：7. 组件实现的基本流程及 Icon 组件的实现</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/osJfi_oOfhEmQJNVqKel3Q" target="_blank" rel="noopener noreferrer">突破 etcd 限制！字节自研 K8s 存储 KubeBrain</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/HPzoclfCB3UxLScXm4J83w" target="_blank" rel="noopener noreferrer">有趣的 Go HttpClient 超时机制</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/F0fpJLcNmiMlS18S0iP3CQ" target="_blank" rel="noopener noreferrer">【综合笔试题】难度 3.5/5，常见序列 DP 题目及其优化思路</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/rNfBHtpFLxwY7-CiBvkQ5A" target="_blank" rel="noopener noreferrer">socket是并发安全的吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/7uobN6DmpIYqG34pOpvvlA" target="_blank" rel="noopener noreferrer">PGO 是啥，咋就让 Go 更快更猛了</a></p><p>📒 <a href="https://juejin.cn/post/7168433475404922910" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 60 期：TypeScript 4.9、Ant Design 5.0、用 vanilla-extract 编写高性能的 CSS</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/dI_gqBOSybThJUb-GNVKyw" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 77 期：布局动画、Arrow JS、vanilla-extract、antd 5、dumi 2</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ws0fcHi-DzCN5PrJNDNKog" target="_blank" rel="noopener noreferrer">三种获取Go项目根目录的方式，让你做架构，选哪种</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mJj3qUw1sPjuX8dVZxvBwA" target="_blank" rel="noopener noreferrer">【第2788期】去哪儿低代码平台跨端渲染方案及落地</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Elq7SWRpH08KmhX7auboOA" target="_blank" rel="noopener noreferrer">Gophers如何准备面试</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Cn-oX0W5DrI2PivaWLDpPw" target="_blank" rel="noopener noreferrer">一步一图带你深入理解 Linux 物理内存管理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/NDC5tEG4GlGTDH_OcJLtfw" target="_blank" rel="noopener noreferrer">「每周译Go」理解 Go 中包的可见性</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/us3NddiVMUADMRU7v-aXKg" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#21 Inefficient slice initialization</a></p><p>📒 Go Time 第 256 期</p><p><a href="https://changelog.com/gotime/256" target="_blank" rel="noopener noreferrer">https://changelog.com/gotime/256</a></p><p>📒 Google Go 风格指南</p><p><a href="https://google.github.io/styleguide/go/index" target="_blank" rel="noopener noreferrer">https://google.github.io/styleguide/go/index</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/VXT6XUoxkZL3LwaN--SUXw" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 168 期 — GoLand 2022.3 RC 发布</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[11月20日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月20日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月20日内容汇总"/>
        <updated>2022-11-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>一个 Next.js 13 的演示教程，里面讲了一个 use 导致的无限循环 bug</p><blockquote><p><a href="https://www.youtube.com/watch?v=zwQs4wXr9Bg" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=zwQs4wXr9Bg</a></p></blockquote><p>如何用 JavaScript 来对 2800 万数据进行去重? — 这是 Stack Overflow 上一个很有趣的问题</p><blockquote><p><a href="https://stackoverflow.com/questions/74329830/deduping-28-million-strings-using-javascript" target="_blank" rel="noopener noreferrer">https://stackoverflow.com/questions/74329830/deduping-28-million-strings-using-javascript</a></p></blockquote><p>Sourcegraph 公司讲述了为什么他们选择从 Monaco 编辑器切换到 CodeMirror</p><blockquote><p><a href="https://about.sourcegraph.com/blog/migrating-monaco-codemirror" target="_blank" rel="noopener noreferrer">https://about.sourcegraph.com/blog/migrating-monaco-codemirror</a></p></blockquote><p>新的 JavaScript 时间 API 提案 --- Temporal（已进入 stage 3）</p><blockquote><p><a href="https://vladmihet.hashnode.dev/temporal-api-javascript-dates-but-better" target="_blank" rel="noopener noreferrer">https://vladmihet.hashnode.dev/temporal-api-javascript-dates-but-better</a></p></blockquote><p>Rome v10：由 Rust 驱动的 JS Linting 与格式化工具 — 由 Babel 的作者 创建的项目自然会引起大家的兴趣</p><blockquote><p><a href="https://rome.tools/blog/2022/11/08/rome-10/" target="_blank" rel="noopener noreferrer">https://rome.tools/blog/2022/11/08/rome-10/</a></p></blockquote><p>Node 安全版本：v19.0.1、v18.12.1、v16.18.1 和 v14.21.1</p><blockquote><p><a href="https://nodejs.org/en/blog/vulnerability/november-2022-security-releases/" target="_blank" rel="noopener noreferrer">https://nodejs.org/en/blog/vulnerability/november-2022-security-releases/</a></p></blockquote><p>Hapi v21：简单、安全的 Node 应用程序框架 - 专注于现代化和全面 Node v18（和 ESM）支持。值得注意的是 Hapi 不光没有外部依赖，还提供了很多开箱即用的功能</p><blockquote><p><a href="https://github.com/hapijs/hapi" target="_blank" rel="noopener noreferrer">https://github.com/hapijs/hapi</a></p></blockquote><p>在多个云提供商上部署一个简单的 Node 应用程序</p><blockquote><p><a href="https://medium.com/eleven-sh/deploying-a-simple-node-js-app-with-https-on-cloud-providers-in-2022-heroku-render-fly-io-aws-9358294803c5" target="_blank" rel="noopener noreferrer">https://medium.com/eleven-sh/deploying-a-simple-node-js-app-with-https-on-cloud-providers-in-2022-heroku-render-fly-io-aws-9358294803c5</a></p></blockquote><p>将 TypeScript 与 Node.js 结合使用</p><blockquote><p><a href="https://www.robinwieruch.de/typescript-node/" target="_blank" rel="noopener noreferrer">https://www.robinwieruch.de/typescript-node/</a></p></blockquote><p>用 Wails 和 React 在 Go 中构建一个桌面应用程序 — Wails 于 Go(lang) 就像 Electron 于 Node 一样，你可以前端用 JavaScript，后端用 GO 在 Mac、Linux 和 Windows 上开发桌面应用程序</p><blockquote><p><a href="https://react.statuscode.com/link/131395/web" target="_blank" rel="noopener noreferrer">https://react.statuscode.com/link/131395/web</a></p></blockquote><p>CRACO v7.0：覆盖 Create React App 配置 — 如果你仍然喜欢 Create React App，而不是如 Next.js 之类的更大的 React 应用构建方式，CRACO 让你继续使用 CRA，但增加了一个可理解的配置层</p><blockquote><p><a href="https://github.com/dilanx/craco" target="_blank" rel="noopener noreferrer">https://github.com/dilanx/craco</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/IO4ynnKEfy2Rt-Me7EIeqg" target="_blank" rel="noopener noreferrer">当谈论协程时，我们在谈论什么</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/bb7C6VNbq7REP9u8PsreSg" target="_blank" rel="noopener noreferrer">看一遍就理解：IO模型详解</a></p><p>⭐️ <a href="https://juejin.cn/post/7167325806778122270" target="_blank" rel="noopener noreferrer">🎉 dumi 2，它来了它来了它来了</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/qaUZ3AMA_dJkx2ZpyhJN2g" target="_blank" rel="noopener noreferrer">面试必备：零拷贝详解</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/UJ59FyXlpTHzj5pzXvk5bQ" target="_blank" rel="noopener noreferrer">2022年我的面试万字总结（代码篇）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/7WU1DDoMYQzXnlstz16QJA" target="_blank" rel="noopener noreferrer">【第2785期】雪球跨端架构建设之跨端容器篇</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/z75HDSlX0PLCnvL5kAcSDw" target="_blank" rel="noopener noreferrer">Go 1.20新特性前瞻</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/DGP1frbIlirZ_C8Vd0OmEA" target="_blank" rel="noopener noreferrer">实战总结！18种接口优化方案的总结</a></p><p>📒 <a href="https://juejin.cn/post/7165411921242357797" target="_blank" rel="noopener noreferrer">深入理解 Golang map 设计理念与实现原理</a></p><p>📒 <a href="https://juejin.cn/post/7165737844613316638" target="_blank" rel="noopener noreferrer">为什么我抓不到baidu的数据包</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XB786byLdrPCGo2pvDcTHw" target="_blank" rel="noopener noreferrer">React这25个精选库，将助你工作更上一层楼</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ADx8PuNvg4xVVLBeh265kw" target="_blank" rel="noopener noreferrer">React 中的重新渲染</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-mw5dqVhmpdEw9xEZqigOA" target="_blank" rel="noopener noreferrer">【常见题型总结】二分以及为何能二分（二段性的拓展）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KegqAAvI4KxDffforTQqKA" target="_blank" rel="noopener noreferrer">保姆级教程！2 万字 + 30 张图搞懂 MySQL 是怎么加行级锁的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Gs48-JTFV_LV3g1nkEYEkA" target="_blank" rel="noopener noreferrer">我修复了一个 Vite Bug，让我的项目首屏性能提高了 25%</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/MztxJRjqMWxmCtoMAiK2eA" target="_blank" rel="noopener noreferrer">Nuxt.js 3.0 正式发布！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bBdO1GSH3Zr5VASCbyhjxQ" target="_blank" rel="noopener noreferrer">【第2784期】从cdnjs 的漏洞来看前端的供应链攻击与防御</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/nBLBnh_NGh_XoN9HZh3XSw" target="_blank" rel="noopener noreferrer">Go1.20 中两个关于 Time 的更新，终于不用背 2006-01-02 15:04:05 了！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/txh_oJGQFlV_VR7NsoU5nA" target="_blank" rel="noopener noreferrer">JavaScript错误处理完整指南</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/E4lT4SuWKIlCZd60i7vigQ" target="_blank" rel="noopener noreferrer">使用反射操作channel</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/2qPeqi3qdk4sqtpqo-3_Uw" target="_blank" rel="noopener noreferrer">成为 Go 高手的 8 个 GitHub 开源项目</a></p><p>🌛 <a href="https://juejin.cn/post/7166187102135123998" target="_blank" rel="noopener noreferrer">使用useReducer + useContext 代替 react-redux</a></p><p>📒 <a href="https://juejin.cn/post/7166108391536869383" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 59 期：GitHub Universe 2022、Rome v10、Parcel v2.8.0、可扩展的 CSS 演变</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/U87wrGsx0Eop3CbF9mlTwQ" target="_blank" rel="noopener noreferrer">万字图文讲透数据库缓存一致性问题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/RuIKpDEuxkhhKiTeVRMXng" target="_blank" rel="noopener noreferrer">【面试高频题】难度 2/5，经典区间 DP 模板题（详解如何思考区间 DP 问题）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6w0YO5l3_69A9z3KRYEizA" target="_blank" rel="noopener noreferrer">打脸了兄弟们，Go1.20 arena 来了！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/PFRJEjxzyLAefWSdniwDoQ" target="_blank" rel="noopener noreferrer">【第2782期】得物API一站式协作平台探索与落地</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zlqZ-4EdzMNt3iubMknKLA" target="_blank" rel="noopener noreferrer">如何在测试中发现goroutine泄漏</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/yyoaDbKsvhdZbAL8T2V-zg" target="_blank" rel="noopener noreferrer">忘了又看，看了又忘？保姆级教学，一口气教你玩转 3 种高频设计模式！</a></p><p>📒 <a href="https://juejin.cn/post/7164175171358556173" target="_blank" rel="noopener noreferrer">【中级/高级前端】为什么我建议你一定要读一读 Tapable 源码</a></p><p>📒 MDH 前端周刊第 76 期：可扩展的 CSS、TanStack Router、Solid Start Beta、Rome 10</p><p>React Router 6 提供了 deferred API，让我们可以区分页面的关键数据和可选数据。可选数据不应该影响页面渲染，比如博客文章的评论、购物车中的推荐产品、最近的搜索等。用法如下。同时可选数据加载报错不会让整体路由渲染报错。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> critical1Promise </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/xxx'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">json</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> critical2Promise </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/xxx'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">json</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> lazy1Promise </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/xxx'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">json</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> lazy2Promise </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/xxx'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">json</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">loader</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">defer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    critical1</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> critical1Promise</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    critical2</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> critical2Promise</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    lazy1</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> lazy1Promise</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    lazy2</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> lazy2Promise</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这和在组件里用 useEffect 有啥区别？useEffect 的方式，不能做到所有请求并行发起，相比之下会慢一些。「The earlier you initiate a fetch, the better, because the sooner it starts, the sooner it can finish.」</p><p><a href="https://dev.to/infoxicator/react-router-6-deferred-fetch-4k68" target="_blank" rel="noopener noreferrer">https://dev.to/infoxicator/react-router-6-deferred-fetch-4k68</a></p><p><a href="https://mp.weixin.qq.com/s/WCXEEe0TgQloYXjwt8rKMg" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 76 期：可扩展的 CSS、TanStack Router、Solid Start Beta、Rome 10</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2CBGgtja04NnOerpKfk0Ug" target="_blank" rel="noopener noreferrer">Node.js 安全最佳实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/4XcnrLk8jYUq56uLSsOMJQ" target="_blank" rel="noopener noreferrer">2种方式！带你快速实现前端截图</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/G7r6abAzKXuite8-E8I12Q" target="_blank" rel="noopener noreferrer">Go学设计模式-程序流程要动态切换？用这个模式写更丝滑</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/r0MnWSMih3mYAaWFalM-Zw" target="_blank" rel="noopener noreferrer">2022 年 JavaScript 从 ES6 到 ES12 新特性汇总</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/d0Sh0tanTJ6x0jsXcA4PFQ" target="_blank" rel="noopener noreferrer">【第2781期】React 渲染的未来</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/n0ETtaQz3r3l0Wx4Y79E9A" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 167 期 —— 结构化日志期待下</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[11月13日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月13日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月13日内容汇总"/>
        <updated>2022-11-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>基于 Amplify Studio 使用少量代码实现 Figma-to-React 组件</p><blockquote><p><a href="https://aws.amazon.com/blogs/mobile/new-build-responsive-figma-to-react-components-with-almost-no-code/" target="_blank" rel="noopener noreferrer">https://aws.amazon.com/blogs/mobile/new-build-responsive-figma-to-react-components-with-almost-no-code/</a></p></blockquote><p>JavaScript 中的 “realm” 是什么</p><blockquote><p><a href="https://weizman.github.io/page-what-is-a-realm-in-js/" target="_blank" rel="noopener noreferrer">https://weizman.github.io/page-what-is-a-realm-in-js/</a></p></blockquote><p>2022 年如何构建，测试并发布一个 TypeScript 编写的 npm 包</p><blockquote><p><a href="https://www.strictmode.io/articles/build-test-and-publish-npm-package-2022" target="_blank" rel="noopener noreferrer">https://www.strictmode.io/articles/build-test-and-publish-npm-package-2022</a></p></blockquote><p>'Next.js 打包出的产物会感谢你' — 如果你的 Next.js 应用打包出的产物比预期的更加大一些，前端工程师 Renato 的打包优化建议会使你受益。</p><blockquote><p><a href="https://renatopozzi.me/articles/your-nextjs-bundle-will-thank-you" target="_blank" rel="noopener noreferrer">https://renatopozzi.me/articles/your-nextjs-bundle-will-thank-you</a></p></blockquote><p>基于 Storybook test runner 实践代码测试的覆盖率</p><blockquote><p><a href="https://storybook.js.org/blog/code-coverage-with-the-storybook-test-runner/" target="_blank" rel="noopener noreferrer">https://storybook.js.org/blog/code-coverage-with-the-storybook-test-runner/</a></p></blockquote><p>教你打包并发布一个 Vue.js 3.0 插件的 npm 包 — 使用 Vite 打包构建出产物，使用 <code>vue-tsc</code> 生成类型带来更好的开发体验。</p><blockquote><p><a href="https://vueschool.io/articles/vuejs-tutorials/how-to-package-and-distribute-a-vue-js-3-plugin-on-npm/" target="_blank" rel="noopener noreferrer">https://vueschool.io/articles/vuejs-tutorials/how-to-package-and-distribute-a-vue-js-3-plugin-on-npm/</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7165503808217284616" target="_blank" rel="noopener noreferrer">Element Plus 组件库相关技术揭秘：6. CSS 架构模式之 BEM 在组件库中的实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/n7obnkSdD_nh4xJtm0-dLw" target="_blank" rel="noopener noreferrer">【第2780期】如何用油猴提升前端开发效率</a></p><p>🌛 <a href="https://mp.weixin.qq.com/s/e0ibggrhNdr_ZAGvxxok2Q" target="_blank" rel="noopener noreferrer">从零实现一个迷你 Webpack</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cW-4yJxqYhYcg8_xrcuHGA" target="_blank" rel="noopener noreferrer">【第2779期】离开后端说前端加密都是空谈</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/8G8CvZAzRNnhsfF6WZoKWg" target="_blank" rel="noopener noreferrer">前缀树在前端路由系统中的应用</a></p><p>📒 <a href="https://juejin.cn/post/7143822279992934436" target="_blank" rel="noopener noreferrer">选择 Go 还是 Rust？CloudWeGo-Volo 基于 Rust 语言的探索实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bSw_QP4-xMKnBTmqAjkUGA" target="_blank" rel="noopener noreferrer">还在服务器上捞日志？快搭建一个ELK日志系统吧，真心强大！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Y_94i7GOcegyQV4pHIrOiw" target="_blank" rel="noopener noreferrer">开启 GODEBUG 更直观地理解 Go 程序的调度过程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-Kt2QJdzEUDJx8MFvrUo7Q" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#20 Not understanding slice length and capacity</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/wKxg6IVZCNK3NG2Os9_3jg" target="_blank" rel="noopener noreferrer">Go 13 周年啦！</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/u5oAcIYiGrl1qOujOYjzqw" target="_blank" rel="noopener noreferrer">基于 MF 的组件化共享工作流</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/5NTgcdhn6CiZ2tg44_T-FQ" target="_blank" rel="noopener noreferrer">快收藏！超强图解Docker常见命令与实战！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zwmFoz0bf8O04fwCLjMiLA" target="_blank" rel="noopener noreferrer">Chrome DevTools中的这些骚操作，你都知道吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Wfy9KgGHlf6SawogMWj34Q" target="_blank" rel="noopener noreferrer">【第2777期】React最新提出了一个名为use的Hook</a></p><p>📒 <a href="https://juejin.cn/post/7158730050718662687" target="_blank" rel="noopener noreferrer">20个常见的前端算法题，你全都会吗</a></p><p>📒 <a href="https://juejin.cn/post/7155434131831128094" target="_blank" rel="noopener noreferrer">阿里面试官：如何给所有的async函数添加try/catch</a></p><p>📒 <a href="https://juejin.cn/post/7146976516692410376" target="_blank" rel="noopener noreferrer">「历时8个月」10万字前端知识体系总结（工程化篇）🔥</a></p><p>📒 React 进阶实践指南 - 渲染控制</p><p><a href="https://juejin.cn/book/6945998773818490884/section/6958058637042384900" target="_blank" rel="noopener noreferrer">https://juejin.cn/book/6945998773818490884/section/6958058637042384900</a></p><p>📒 如何用 TypeScript 声明 React HOC</p><p><a href="https://react-typescript-cheatsheet.netlify.app/docs/hoc/full_example" target="_blank" rel="noopener noreferrer">https://react-typescript-cheatsheet.netlify.app/docs/hoc/full_example</a></p><p><a href="https://medium.com/@jrwebdev/react-higher-order-component-patterns-in-typescript-42278f7590fb" target="_blank" rel="noopener noreferrer">https://medium.com/@jrwebdev/react-higher-order-component-patterns-in-typescript-42278f7590fb</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/iZ3JR0OVnlUi0asyJ6OFtA" target="_blank" rel="noopener noreferrer">云谦：前端框架的趋势与实践（文字稿）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/xxIyA7Hcq_vn6RzM-gUEhA" target="_blank" rel="noopener noreferrer">这30 个优秀的 Go 编码习惯，你都在用吗</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/xzNqpRbIvoJygSWeQJFjTw" target="_blank" rel="noopener noreferrer">一文搞懂Go标准库context包</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KlhCgke0WQP8g2t0QLu4Zg" target="_blank" rel="noopener noreferrer">记一次使用time.Duration类型踩过的坑</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-e-Mlyd9x2OyybCDGE2Pog" target="_blank" rel="noopener noreferrer">golang中time包使用教程之基础使用篇</a></p><p>⭐️ <a href="https://juejin.cn/post/7124337913352945672" target="_blank" rel="noopener noreferrer">字节开源WEB框架Hertz太香啦！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/wugntKhMZpgr6RtB1AwAmQ" target="_blank" rel="noopener noreferrer">面试必问之 JS 事件循环（Event Loop），看这一篇足够</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ete4-_Yxu84_Er5gZjPiwg" target="_blank" rel="noopener noreferrer">信仰崩了？Preact 开始采用 Vue3 的响应式设计</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/kDkt1YalJHck5-bdAC-pAA" target="_blank" rel="noopener noreferrer">【常见题型总结】序列 DP 模板题（总结「线性 DP」和「序列 DP」本质区别）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/i0Rd4t24Xi0zgmWLeLmplg" target="_blank" rel="noopener noreferrer">点击页面元素跳转IDE对应代码，试试这几个工具！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ZOdasSP0paVCLF94Vf9A9A" target="_blank" rel="noopener noreferrer">Go 十年了，终于想起要统一 log 库了！</a></p><p>📒 <a href="https://juejin.cn/post/7163235734361473055" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 58 期：TypeScript 4.9 RC、10 月登陆浏览器的新功能、Turbopack 真的比 Vite 快 10 倍吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/WLMeCUG0V5369XXb4Bs4CQ" target="_blank" rel="noopener noreferrer">由 transform 被占用引发的思考🤔</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2VIxDcCUY5nrLFFF2R084A" target="_blank" rel="noopener noreferrer">TypeScript 4.9 发布！重点新特性解读 ～</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/FrMXld9HgL98hi4XzMmEvA" target="_blank" rel="noopener noreferrer">聊一聊常见的浏览器数据存储方案</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/ST-C62ckSXnjlU6Gag3E5Q" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 75 期：CSS-in-JS、Node 18、完美提交、ChiselStrike、Ultra</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/u8pXAxs1nMgNSzAQZIK3YQ" target="_blank" rel="noopener noreferrer">Happens before 原则在 Go 内存模型中的应用举例</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/kyGNVNDby5uq5JGfQt4Yrg" target="_blank" rel="noopener noreferrer">这些最常用的 Go CLI 命令，新手 Gopher 应该掌握</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/S0I8xNAuYbP4JvxahpNG6Q" target="_blank" rel="noopener noreferrer">「每周译Go」如何在 Go 中编写包</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[11月6日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月6日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/11月6日内容汇总"/>
        <updated>2022-11-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 相关文章推荐]]></summary>
        <content type="html"><![CDATA[<p>📒 相关文章推荐</p><p>理解 useMemo and useCallback</p><blockquote><p><a href="https://www.joshwcomeau.com/react/usememo-and-usecallback/" target="_blank" rel="noopener noreferrer">https://www.joshwcomeau.com/react/usememo-and-usecallback/</a></p></blockquote><p>React 错误边界指南</p><blockquote><p><a href="https://meticulous.ai/blog/react-error-boundaries-complete-guide/" target="_blank" rel="noopener noreferrer">https://meticulous.ai/blog/react-error-boundaries-complete-guide/</a></p></blockquote><p>何时使用 useLayoutEffect 而不是 useEffect</p><blockquote><p><a href="https://javascript.plainenglish.io/react-hooks-when-to-use-uselayouteffect-instead-of-useeffect-3271a96d881a?gi=622ccbf807f3" target="_blank" rel="noopener noreferrer">https://javascript.plainenglish.io/react-hooks-when-to-use-uselayouteffect-instead-of-useeffect-3271a96d881a?gi=622ccbf807f3</a></p></blockquote><p>深度解析好文：为了让 React 更好</p><blockquote><p><a href="https://acko.net/blog/get-in-zoomer-we-re-saving-react/" target="_blank" rel="noopener noreferrer">https://acko.net/blog/get-in-zoomer-we-re-saving-react/</a></p></blockquote><p>创建现代 npm 包的最佳实践</p><blockquote><p><a href="https://snyk.io/blog/best-practices-create-modern-npm-package/" target="_blank" rel="noopener noreferrer">https://snyk.io/blog/best-practices-create-modern-npm-package/</a></p></blockquote><p>useSyncExternalStore：被低估的 React API</p><blockquote><p><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api" target="_blank" rel="noopener noreferrer">https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api</a></p></blockquote><p>为什么每个 React 开发者都应该学习函数组合</p><blockquote><p><a href="https://medium.com/javascript-scene/why-every-react-developer-should-learn-function-composition-23f41d4db3b1" target="_blank" rel="noopener noreferrer">https://medium.com/javascript-scene/why-every-react-developer-should-learn-function-composition-23f41d4db3b1</a></p></blockquote><p>“为什么我们要放弃 CSS-in-JS” - Emotion 是一个用 JavaScript 编写 CSS 的流行库，但它的一位贡献者讲述了为什么他的团队总体上放弃了 CSS-in-JS 的想法。</p><blockquote><p><a href="https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b" target="_blank" rel="noopener noreferrer">https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b</a></p></blockquote><p>在 React 中使用 <code>use</code> - 一个新的 Hook 即将到来</p><blockquote><p><a href="https://vived.io/new-hook-is-coming-to-react-frontend-weekly-vol-109/" target="_blank" rel="noopener noreferrer">https://vived.io/new-hook-is-coming-to-react-frontend-weekly-vol-109/</a></p></blockquote><p>⭐️ <a href="https://juejin.cn/post/7162775935828115469" target="_blank" rel="noopener noreferrer">理解 Next.js 中的 CSR、SSR、SSG、ISR 以及 Streaming</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/Fqy_pkgKvZrdZZc3t5xgdA" target="_blank" rel="noopener noreferrer">【第2774期】基于 Module Federation 的模块化跨栈方案探索</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/z-tKxgRPmdyR0zwc78Khgw" target="_blank" rel="noopener noreferrer">组件库Monmrepo架构与开发调试环境构建</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/CG5plqmv1-pFT-qRDJk-nQ" target="_blank" rel="noopener noreferrer">你了解 Cookie 中的 SameSite 属性吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bEaL-TYR0aNMwWZWYgXnWA" target="_blank" rel="noopener noreferrer">配个 json，表单就出来了？FormRender 初探</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/dG58Dtml2FfU_aANJCgkfQ" target="_blank" rel="noopener noreferrer">Go每日一库之调用外部命令的几种姿势</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hyfa1NIeMoBbdiIbGVDkFg" target="_blank" rel="noopener noreferrer">带你提前看看 Go 1.20 包括哪些重大变更和性能提升</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/C_8NZLx4TOX-8Xw5q4Xzyg" target="_blank" rel="noopener noreferrer">GitHub上高质量数据结构与算法项目推荐！</a></p><p>📒 如何使用官方的 Node.js Docker 镜像</p><p><a href="https://www.docker.com/blog/how-to-use-the-node-docker-official-image/" target="_blank" rel="noopener noreferrer">https://www.docker.com/blog/how-to-use-the-node-docker-official-image/</a></p><p>📒 Node v18 现在进入 LTS 阶段（v18.12.0）</p><p>直至 2023 年 10 月，之前作为 current 版本的 v18 将作为 active LTS 存在，并拥有所有最新的功能特性。本版本的代号是 “氢”——宇宙中最丰富的元素。</p><p><a href="https://nodejs.org/en/blog/release/v18.12.0/" target="_blank" rel="noopener noreferrer">https://nodejs.org/en/blog/release/v18.12.0/</a></p><p>📒 route-list：显示 Express/Koa/Hapi/Fastify 路由</p><p>如果你想以一种优雅的方式查看基于 Node 的 webapp 的所有路由，那么可以试试它。</p><p><a href="https://github.com/VladimirMikulic/route-list" target="_blank" rel="noopener noreferrer">https://github.com/VladimirMikulic/route-list</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/LkM_Y-9OfgXatocVsM6m6g" target="_blank" rel="noopener noreferrer">现代 CSS 指南 -- at-rule 规则必知必会</a></p><p>📒 深入浅出 Vite - 推荐阅读</p><ul><li><a href="https://juejin.cn/book/7050063811973218341/section/7070419010021490702" target="_blank" rel="noopener noreferrer">手写 Bundler: 实现代码打包、 Tree Shaking</a></li><li><a href="https://juejin.cn/book/7050063811973218341/section/7066614663533821983" target="_blank" rel="noopener noreferrer">手写 Bundler: 实现 JavaScript AST 解析器——词法分析、语义分析</a></li></ul><p>📒 开发小技巧</p><p>npm scripts 中的 <code>--</code> 可以用来转发命令行参数：</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"build:weapp"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"taro build --type=miniprogram"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"dev:weapp"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm run build:weapp -- --watch"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>⭐️ <a href="https://juejin.cn/post/7161303856943464455" target="_blank" rel="noopener noreferrer">极致编译速度，一文搞定webpack5升级</a></p><p>📒 <a href="https://juejin.cn/post/7161063570594070559" target="_blank" rel="noopener noreferrer">Element Plus 组件库核心技术揭秘：5. 从终端命令解析器说起谈谈 npm 包管理工具的运行原理</a></p><p>📒 <a href="https://juejin.cn/post/7161063643105198093" target="_blank" rel="noopener noreferrer">一文吃透 React 和 Vue 的多节点 diff 原理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/tc0amzQ5HDRTfORdq11RBg" target="_blank" rel="noopener noreferrer">看 Go 中的 struct 如何被优化，还有小插曲</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Pcp2FjcXk7Q7sV0Z-bEUNw" target="_blank" rel="noopener noreferrer">Go for 循环有时候真的很坑</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-Ysho1jI9MfrAIrplzj7UQ" target="_blank" rel="noopener noreferrer">用Go学设计模式-提炼流程，减少重复开发就靠它了!</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/aERKozDPGPdrePl21mN9JA" target="_blank" rel="noopener noreferrer">vue中动态引入图片为什么要是require， 你不知道的那些事</a></p><p>⭐️ <a href="https://juejin.cn/post/7157902763534319624" target="_blank" rel="noopener noreferrer">聊一聊常见的构建工具关于插件机制的那些通用套路</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6Rr1UfMTa-Y6H7_VAtv0aw" target="_blank" rel="noopener noreferrer">Chrome 最近带来了哪些有意思的新东西</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JbmA1NK4CWOiD0gOTXa_AA" target="_blank" rel="noopener noreferrer">深入剖析容器技术基础</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1bUGWcOfvdBR1vLDp_T6Qw" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 57 期：Turbopack、Next.js13、Chrome107、Vite3.2、图解 TLS 1.3</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/025-MLMAbdT38kWI--AoYg" target="_blank" rel="noopener noreferrer">Go 语言终极搜索插件</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cFwqrnpww-kNL7-JRoydBA" target="_blank" rel="noopener noreferrer">压缩 70% 下载流量 - 记一次店铺优化专项</a></p><p>📒 我们如何用 Next.js 提高 70% 的 React 加载时间</p><p>通过用 Next.js 替换 Create React App，商业计划平台 Causal 通过减少加载时间显著改善了用户体验。怎么做到的？一点 SSR 就能帮你很多。</p><p><a href="https://www.causal.app/blog/next-js" target="_blank" rel="noopener noreferrer">https://www.causal.app/blog/next-js</a></p><p>📒 “为什么我们要放弃 CSS-in-JS”</p><p>Emotion 是一个用 JavaScript 编写 CSS 的流行库，但它的一位贡献者讲述了为什么他的团队总体上放弃了 CSS-in-JS 的想法。</p><p><a href="https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b" target="_blank" rel="noopener noreferrer">https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b</a></p><p>📒 在 React 中使用 <code>use</code> - 一个新的 Hook 即将到来</p><p>上周我们在一个叫做 use 的新 Hook 后面介绍了 RFC —— 这里有一个更容易理解的介绍。“这个不起眼的发明可能永远改变我们将数据输入应用程序的方式。”</p><p><a href="https://vived.io/new-hook-is-coming-to-react-frontend-weekly-vol-109/" target="_blank" rel="noopener noreferrer">https://vived.io/new-hook-is-coming-to-react-frontend-weekly-vol-109/</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/94thx36Ao2PYQ-8Cbto-wQ" target="_blank" rel="noopener noreferrer">程序员应该遵守的编程原则(不止Gopher哦)</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mL1pv2kPKvtaHalr7PXKow" target="_blank" rel="noopener noreferrer">前端工程化基建探索：从内部机制和核心原理了解npm</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/f1N7FhlNshEP30s9ph_R8Q" target="_blank" rel="noopener noreferrer">哈啰下一代跨技术栈前端组件库 Quark Design 正式开源！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6EdUBn3Dk_F9BgBQfLwpRQ" target="_blank" rel="noopener noreferrer">深入浅出JavaScript异步编程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6KxJRG3lKUDY734t4EzAaA" target="_blank" rel="noopener noreferrer">深度解密Go语言之关于 interface 的 10 个问题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/qyEiEACuUd8SsyqCDLUjXA" target="_blank" rel="noopener noreferrer">手撸源码系列 - cache2go</a></p><p>📒 《 关于我用拓展运算符把项目搞崩这件事 》</p><p>注意函数调用不能接受过长的参数：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> items </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> newItems</span><span class="token operator" style="color:#393A34">=</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name builtin">Array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1000000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ❎ 以下两种情况，如果 newItems 很长容易导致爆栈问题</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">newItems</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">apply</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> newItems</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 合理做法</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">concat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">newItems</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">items </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">...</span><span class="token plain">items</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">newItems</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://mp.weixin.qq.com/s/vmlVUwM05PEZj15doanLaA" target="_blank" rel="noopener noreferrer">《 关于我用拓展运算符把项目搞崩这件事 》</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/EcShs5E7lH7jdQGMttFmYA" target="_blank" rel="noopener noreferrer">前端性能优化到底该怎么做（下）- 直捣黄龙</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/0h9pGl04-9AsbF_OTF8TSg" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 165 期 —— 基于 fyne 实现一个简单计算器</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[10月30日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月30日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月30日内容汇总"/>
        <updated>2022-10-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Next.js 13 相关文章]]></summary>
        <content type="html"><![CDATA[<p>📒 Next.js 13 相关文章</p><p><a href="https://juejin.cn/post/7160084572942630926" target="_blank" rel="noopener noreferrer">你好，Next.js 13</a></p><p><a href="https://nextjs.org/blog/next-13" target="_blank" rel="noopener noreferrer">https://nextjs.org/blog/next-13</a></p><p><a href="https://beta.nextjs.org/docs/data-fetching/fundamentals#" target="_blank" rel="noopener noreferrer">https://beta.nextjs.org/docs/data-fetching/fundamentals#</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/N0CZABDD0TKTmdljH3y74A" target="_blank" rel="noopener noreferrer">Monorepo，大型前端项目管理模式实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/vnq-CIfYtosaj49Nq_wn7A" target="_blank" rel="noopener noreferrer">React Hooks不优雅</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/oDOH-xNojT8_K4RsMLNSuw" target="_blank" rel="noopener noreferrer">运用「博弈论」分析「先手必胜态」序列具有何种性质，以及如何思考「博弈论」问题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/LnsVooXr-S-EkAoRj_ha5A" target="_blank" rel="noopener noreferrer">Go 大佬良心发现，愿意给 map 加清除了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-sJmOZ8ObGEe3X9QZNqlWA" target="_blank" rel="noopener noreferrer">Turbopack 很火? 那么就从前端角度看 Rust</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ll_7eYp_BJ2yJO-7bsR1IQ" target="_blank" rel="noopener noreferrer">Docker夺命连环15问，你能坚持第几问</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/0jyXab9o2nizmVa9CANLOA" target="_blank" rel="noopener noreferrer">当函数设计遇到切片</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/4Za4c_XxVLnUlYoqSeU7Aw" target="_blank" rel="noopener noreferrer">使用Go语言批量同步微信读书笔记到Flomo</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/rH2BqV2v7O-2KYVYNaZU-Q" target="_blank" rel="noopener noreferrer">一文了解 NextJS 并对性能优化做出最佳实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/SRp408d-7T8nsPU4WjlMrQ" target="_blank" rel="noopener noreferrer">比Webpack快700倍的Turbopack，到底快在哪</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/beLkwHan2C8BuSArs53cIA" target="_blank" rel="noopener noreferrer">课代表：Turborepo 笔记</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/n4Xvjrze4lWx8HdSMN20tg" target="_blank" rel="noopener noreferrer">Go标准库依赖的那些modules</a></p><p>📒 <a href="https://juejin.cn/post/7158478077670981662" target="_blank" rel="noopener noreferrer">使用 Vitest 和 React Testing Library 给 Next.js 应用单元测试</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zxSv8IpJtR__--pIwwb6AQ" target="_blank" rel="noopener noreferrer">前端初学 ECS 架构，实现超炫的粒子碰撞动画</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/X4LSkIOjsoyXPB2z8AxtFA" target="_blank" rel="noopener noreferrer">Go HTTP服务用了优雅关闭，为什么还是报错</a></p><p>⭐️ <a href="https://juejin.cn/post/7147245442172977189" target="_blank" rel="noopener noreferrer">【羊了个羊】之我用vue3+ts+vite3从0到1开发了个【兔了个兔】</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/oDXzrZcHJ_MhqIToqqaTHw" target="_blank" rel="noopener noreferrer">【第2763期】接入成本最低微前端框架：京东零售micro-app</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/l_KKNRUyJANN6wkoC2TlVQ" target="_blank" rel="noopener noreferrer">聊一聊关于微前端架构的几种技术选型</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/UDru9Wxr53FH4sjq9MWBUA" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 56 期：Solid v1.6.0、State of GraphQL、ViteConf回放、Lerna v6</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/WocipcJ3b1VTg2MYJyRdwA" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 74 期：use、htmx、Stately Studio、TypeRunner、画中画</a></p><p>📒 <a href="https://juejin.cn/post/7129298214959710244" target="_blank" rel="noopener noreferrer">一文教你搞定所有前端鉴权与后端鉴权方案，让你不再迷惘</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ipbUy3GBRMFat9jUSssMMw" target="_blank" rel="noopener noreferrer">1024，我们的节日，Gopher 该干点啥</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/o5F5obAXuFSpKYrn2r1FZw" target="_blank" rel="noopener noreferrer">Go try 新提案靠谱吗？想简化错误处理了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KgjK7NJtkJbSRC7ToTJGdA" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#18 Neglecting integer overflows</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/e-pES-WWY3LJSQI9Cpj30Q" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 164 期</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[10月23日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月23日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月23日内容汇总"/>
        <updated>2022-10-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 React 服务端渲染在跨端领域中的新视界]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7156607920262610981" target="_blank" rel="noopener noreferrer">React 服务端渲染在跨端领域中的新视界</a></p><p>📒 <a href="https://juejin.cn/post/7124112069355372581" target="_blank" rel="noopener noreferrer">学会这 20 个库，让你快速看懂 vue3 和 vite3 源码 🚀</a></p><p>📒 <a href="https://juejin.cn/post/7094984070999834655" target="_blank" rel="noopener noreferrer">面试官：你会看 Vite 源码吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/wz2cyouDMCwbc38S-qOsAg" target="_blank" rel="noopener noreferrer">用 Go 程序打包和压缩文件，我们可以这么做</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Jc30Ro4D9vD9kVwPG_VPIA" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#17 Creating confusion with octal literals</a></p><p>📒 如何挑选最适合的 Node.js Docker 镜像</p><p>当你在编写 DockerFile 时会忽略 <code>FROM node</code> 的含义，作者分享了一些对于版本选择上的考虑。</p><p><a href="https://snyk.io/blog/choosing-the-best-node-js-docker-image/" target="_blank" rel="noopener noreferrer">https://snyk.io/blog/choosing-the-best-node-js-docker-image/</a></p><p>📒 Lerna Reborn：第六个版本更新了什么</p><p>使用 Nrwl 管理，面向 Lerna monorepo 的 JavaScript 构建系统并没有过时或弃用，它正在向前迈进一大步。v6 在默认情况下通过高效的任务调度和缓存、VS Code 扩展、Prettier 支持等获得了很大的速度。</p><p><a href="https://blog.nrwl.io/lerna-reborn-whats-new-in-v6-10aec6e9091c?gi=ba929beec06d" target="_blank" rel="noopener noreferrer">https://blog.nrwl.io/lerna-reborn-whats-new-in-v6-10aec6e9091c?gi=ba929beec06d</a></p><p>📒 Node v18.11.0 发布</p><p>Node 的最新版本虽然并没有更新很多功能，但却实验性的支持了 <code>--watch</code> 功能。当导入的文件发生变化时，会自动重新启动运行中的进程（这个功能让人想起了 <code>nodemon</code>） – 这个功能最近被 <code>详细讨论过</code>。</p><p><a href="https://nodejs.org/en/blog/release/v18.11.0/" target="_blank" rel="noopener noreferrer">https://nodejs.org/en/blog/release/v18.11.0/</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KA9Zvnkye6bIgzbP_MT6Iw" target="_blank" rel="noopener noreferrer">【综合笔试题】难度 4.5/5，扫描线的特殊运用（详尽答疑）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6peafvVjmcF65PFSggSLYQ" target="_blank" rel="noopener noreferrer">复活了！ Lerna V6 带来了哪些新东西</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/3MwRLM0jDmwv5l6gamFjcw" target="_blank" rel="noopener noreferrer">【第2757期】软件架构的23个基本原则</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/iB23DV4hovPDdf5_4TCaOA" target="_blank" rel="noopener noreferrer">【第2677期】如何在React中应用SOLID原则</a></p><p>📒 <a href="https://juejin.cn/post/7124573626161954823" target="_blank" rel="noopener noreferrer">前端架构带你 封装axios，一次封装终身受益「美团后端连连点赞」</a></p><p>📒 如何编写 CommonJS 模块，以便它们的导出可以从 ES 模块实现按照名称导入</p><p>如果你曾经在使用 CommonJS 和 ES 模块之间纠结过，那么这篇文章或许值得一读。Axel 博士在这里解决了一个关键的交叉兼容性问题。</p><p><a href="https://2ality.com/2022/10/commonjs-named-exports.html" target="_blank" rel="noopener noreferrer">https://2ality.com/2022/10/commonjs-named-exports.html</a></p><p>📒 njt：快速导航至 npm 包资源</p><p>如果你想要快速访问 npm 包的首页、仓库、issues，甚至包成本估算，那么 njt 将会是一个不错的选择。njt 提供了一个快速跳转到与 npm 包相关的各种资源目的地的方法。你可以在终端中安装并使用，也可以通过 LaunchX 扩展程序 将 njt 添加至 VS Code 的命令面板然后使用，或者在 Google 与 Firefox 浏览器进行配置然后搜索，亦或 直接在网页上使用它。如果你对此有兴趣，可以来看看 GitHub 仓库。</p><p><a href="https://www.npmjs.com/package/njt" target="_blank" rel="noopener noreferrer">https://www.npmjs.com/package/njt</a></p><p>📒 <a href="https://juejin.cn/post/7142653628904701988" target="_blank" rel="noopener noreferrer">换一种方式对工程中的Api进行封装吧（fashion-axios）</a></p><p>📒 <a href="https://juejin.cn/post/7153659360177029150" target="_blank" rel="noopener noreferrer">Element Plus 组件库相关技术揭秘：3.ESLint 核心原理剖析</a></p><p>📒 <a href="https://juejin.cn/post/7146183222425518093" target="_blank" rel="noopener noreferrer">Element Plus 组件库相关技术揭秘：2. 组件库工程化实战之 Monorepo 架构搭建</a></p><p>📒 开源推荐</p><p><strong>lazygit</strong></p><p>git 命令的 terminal UI 工具，基于 Go 实现。</p><p><a href="https://github.com/jesseduffield/lazygit" target="_blank" rel="noopener noreferrer">https://github.com/jesseduffield/lazygit</a></p><p><strong>knip</strong></p><p>又一个废代码检测工具，支持检测未使用的文件、依赖和 exports。</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ knip --reporter codeowners</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--- UNUSED FILES </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/team src/chat/helpers.ts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/components/SideBar.tsx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--- UNUSED DEPENDENCIES </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/admin moment</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--- UNLISTED DEPENDENCIES </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/components/Registration.tsx react</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--- UNUSED EXPORTS </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/team src/common/src/string/index.ts: lowercaseFirstLetter</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/components/Registration.tsx: RegistrationBox</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/css.ts: clamp</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/services/authentication.ts: restoreSession, PREFIX</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--- UNUSED TYPES </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/components/Registration/registrationMachine.ts: RegistrationServices, RegistrationAction</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/components/Registration.tsx: ComponentProps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/types/Product.ts: ProductDetail</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--- DUPLICATE EXPORTS </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/components/Registration.tsx: Registration, default</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@org/owner src/components/Products.tsx: ProductsList, default</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://github.com/webpro/knip" target="_blank" rel="noopener noreferrer">https://github.com/webpro/knip</a></p><p>📒 手写 React 渲染器</p><p>由于有 react-reconciler，让自定义 React 渲染器变地相当简单。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">ReactReconciler</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-reconciler"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> reconciler </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">ReactReconciler</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ... configuration options ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 启用突变模式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Reconciler 有两种不同的渲染模式，1）突变模式，2）持久模式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">supportsMutation</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">createInstance</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">type</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> element </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">type</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">keys</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">prop</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// Filter out non-HTML attributes like:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"children"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"onClick"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"key"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">includes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">prop</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// Appends each html attribute to the element</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        element</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">prop</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> props</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">prop</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// return the HTML element</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> element</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">createTextInstance</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">text</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createTextNode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">getRootHostContext</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">getChildHostContext</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">shouldSetTextContent</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">prepareForCommit</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">clearContainer</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">resetAfterCommit</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">appendInitialChild</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">appendChildToContainer</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">finalizeInitialChildren</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">removeChildFromContainer</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">element</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> container</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> root </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> reconciler</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createContainer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">container</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    reconciler</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">updateContainer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">element</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token exports punctuation" style="color:#393A34">{</span><span class="token exports"> render </span><span class="token exports punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>然后就可以拿这个 <code>render</code> 方法进行渲染了。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">App</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getElementById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'root'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://www.markcodes.dev/posts/build-react-custom-renderer-part-1" target="_blank" rel="noopener noreferrer">https://www.markcodes.dev/posts/build-react-custom-renderer-part-1</a></p><p>📒 最快前端模板</p><p>Jest 作者梳理了他认为最快的 2022 最快前端工具集以及与之配套的 github 仓库模板，结论是 Vite + tailwind + pnpm + eslint &amp; prettier + TypeScript + React。我觉得这里的快有两个含义，1）速度快，2）用于快速启动项目的最小模板。</p><ul><li>Vite 无需多说</li><li>Tailwind 也无需多说，但如果你有自己的 Design System，作者推荐用 emotion</li><li>pnpm 除了快，对 monorepo 的支持也很好</li><li>ESLint &amp; prettier 有一些注意点，1）要分开用，别在 eslint 规则里加 prettier 规则，会慢，2）prettier 和 eslint 都有 --cache 参数，要开启，3）推荐用 @trivago/prettier-plugin-sort-imports 和 prettier-plugin-tailwindcss 对 import 和 tailwindcss 类进行排序，4）期待 rome 的 formatter 和 lint</li><li>npm-run-all 用于并行执行多个命令</li><li>NodeJS 脚本编写，基于 native esm，使用 ts-node + @swc/core + nodemon 的依赖组合实现，没有用基于 esbuild 方案比如 tsx，因为测下来在一些场景会莫名其妙地慢</li><li>TypeScript 无需多说</li><li>VSCode，作者推荐了 4 个插件</li></ul><p>大家可能会好奇，作为 Jest 作者，测试工具他选的啥？虽然文章里没提，但从代码里可以看到，用的是 Vitest，哈哈。</p><p><a href="https://cpojer.net/posts/fastest-frontend-tooling-in-2022" target="_blank" rel="noopener noreferrer">https://cpojer.net/posts/fastest-frontend-tooling-in-2022</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/GaSo704nCAOba7d3XhwCzg" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 73 期：TypeScript 10 年、最快前端模板、whyframe、template 元素</a></p><p>📒 文章推荐</p><ul><li><a href="https://supercodepower.com/fontend-target" target="_blank" rel="noopener noreferrer">🗂 前端版本兼容问题的探索</a></li><li><a href="https://supercodepower.com/web-dev-blog" target="_blank" rel="noopener noreferrer">🗂 对 web.dev 所有 blog 的整理与归档</a></li><li><a href="https://supercodepower.com/react-native-tweet" target="_blank" rel="noopener noreferrer">🤯 没 2 年 React Native 开发经验，你都遇不到这些坑</a></li></ul><p>📒 Storybook 7.0 中 Vite 成为内置选项</p><p><a href="https://storybook.js.org/blog/first-class-vite-support-in-storybook/" target="_blank" rel="noopener noreferrer">https://storybook.js.org/blog/first-class-vite-support-in-storybook/</a></p><p>📒 用 Sandpack 打造世界级 Playground</p><p>CodeSandbox 开源了 Sandpack，本文教你使用 Sandpack 打造出一个功能齐全的 Playground。</p><p><a href="https://www.joshwcomeau.com/react/next-level-playground/" target="_blank" rel="noopener noreferrer">https://www.joshwcomeau.com/react/next-level-playground/</a></p><p>📒 Resumable vs. Hydration</p><p>本文介绍了 Qwik 框架可恢复性的实现原理以及与常规补水相比具有的优势。</p><p><a href="https://qwik.builder.io/docs/concepts/resumable/" target="_blank" rel="noopener noreferrer">https://qwik.builder.io/docs/concepts/resumable/</a></p><p>📒 <a href="https://devblogs.microsoft.com/typescript/ten-years-of-typescript/" target="_blank" rel="noopener noreferrer">TypeScript 十年，不忘初心</a></p><p>📒 Rollup v3.0.0</p><p>Rollup 发布 v3.0.0，带来了大量更新。其中 Breaking Change 包括最低支持 Node 14.18.0、浏览器构建拆成单独的包 @rollup/browse、Node 构建使用 <code>node:</code> 前缀导入内置模块、移除一些以前被废弃的功能，使用时提示警告等。还有包括 Options 配置、插件 API、以及一系列的新特性。</p><blockquote><p>Rollup 3.0 意味着 Vite 即将发布大版本</p></blockquote><p><a href="https://github.com/rollup/rollup/releases/tag/v3.0.0" target="_blank" rel="noopener noreferrer">https://github.com/rollup/rollup/releases/tag/v3.0.0</a></p><p>📒 <a href="https://juejin.cn/post/7155435611619328036" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 55 期：Rollup v3.0.0、Volar 1.0 Nika、TypeScript 十年</a></p><p>📒 如何使用 React、SSR 和 Tailwind CSS 构建 SVG 折线图</p><p>关于如何在基于 Next.js 或 Gatsby 的服务器端渲染 React 应用程序中创建你自己的基于 SVG 的折线图的教程。</p><p><a href="https://thenewstack.io/how-to-build-svg-line-charts-with-react-ssr-and-tailwind-css/" target="_blank" rel="noopener noreferrer">https://thenewstack.io/how-to-build-svg-line-charts-with-react-ssr-and-tailwind-css/</a></p><p>📒 React 渲染的未来</p><p>首先回顾当前的渲染模式 (CSR/SSR)然后转向一些新的渲染模式，例如流式 SSR 和服务器组件。这也是在 React Bangalore 的 最近访谈 中的话题。</p><p><a href="https://prateeksurana.me/blog/future-of-rendering-in-react/" target="_blank" rel="noopener noreferrer">https://prateeksurana.me/blog/future-of-rendering-in-react/</a></p><p>📒 React Table：一个 “几乎无头” 的表格组件</p><p><a href="https://react-table-library.com/" target="_blank" rel="noopener noreferrer">https://react-table-library.com/</a></p><p>📒 <a href="https://juejin.cn/post/7155300194773860382" target="_blank" rel="noopener noreferrer">Islands 架构原理和实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/BAOrH_-UWliOOc0pFGct-w" target="_blank" rel="noopener noreferrer">你不需要Next.js（和SSR）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/vRiqSVSQOVsShnblV_fDfw" target="_blank" rel="noopener noreferrer">【面试高频题】难度 1.5/5，常规滑动窗口运用题</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/-PSUUDk0JtYRYH7g0viTZg" target="_blank" rel="noopener noreferrer">精读《Headless 组件用法与原理》</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/TcYo3VWpM3uDpya1XXrX3w" target="_blank" rel="noopener noreferrer">学习了！GoMap 会内存泄露</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/MSGH09uUjSquxGlxnBIUBg" target="_blank" rel="noopener noreferrer">如何让 Go 反射变快</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/cAwc6ZhdUwxkI5VT8LY9Hg" target="_blank" rel="noopener noreferrer">Go Gin框架请求自动验证和数据绑定，看完这篇就会用了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/WfjnwzZvBsymk_DyhAV_6g" target="_blank" rel="noopener noreferrer">一文搞懂Go内联优化</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/nc4s289ULpQkGlQuaFbZlQ" target="_blank" rel="noopener noreferrer">Go常见错误集锦之函数式选项模式</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fVSi3-J7tnaP2AqunW9fWw" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 163 期 —— 错误处理新提案</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[10月16日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月16日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月16日内容汇总"/>
        <updated>2022-10-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 开发小技巧总结]]></summary>
        <content type="html"><![CDATA[<p>📒 开发小技巧总结</p><p>如何优雅删除数组中的元素：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">imageList</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setImageList</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">handleRemoveImage</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">idx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 第一种：mutable 方式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 由于 `splice` 方法直接修改原数组，所以数组指针实际上没有变化</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 当 setState 的时候，React 内部使用 `Object.is` 严格相等比较</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 由于指针没有改变，不会触发 React 调度更新</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 这里需要手动浅拷贝，创建一个新数组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  imageList</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">splice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">idx</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">setImageList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">imageList</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 第二种：immutable 方式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 用 `filter` 返回一个新数组，简单直接</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">setImageList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">l </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> l</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> index </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> idx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/M4pDRfwCdUW0vxrAojxXZg" target="_blank" rel="noopener noreferrer">如何优雅地编写一个高逼格的JS插件</a></p><p>📒 <a href="https://juejin.cn/post/7154175507280429070" target="_blank" rel="noopener noreferrer">React 渲染的未来</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ItQbMlTYFhZUJSDFty3ULA" target="_blank" rel="noopener noreferrer">不破不立 —— 挥别 less-loader，Ant Design 5.0 Alpha 发布</a></p><p>📒 <a href="https://juejin.cn/post/7152045316294836260" target="_blank" rel="noopener noreferrer">Vue3组件库打包指南，一次生成esm、esm-bundle、commonjs、umd四种格式</a></p><p>📒 <a href="https://juejin.cn/post/7148969678642102286" target="_blank" rel="noopener noreferrer">Three.js 进阶之旅：模型光源结合生成明暗变化的创意页面-光与影之诗 💡</a></p><p>📒 <a href="https://juejin.cn/post/7146383940931026958" target="_blank" rel="noopener noreferrer">Three.js 进阶之旅：基础入门（下）</a></p><p>📒 <a href="https://juejin.cn/post/7145064095178293285" target="_blank" rel="noopener noreferrer">Three.js 进阶之旅：基础入门（上）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/8cguocg_1DtZkHLfAGLyXg" target="_blank" rel="noopener noreferrer">使用 Vite 插件自动化实现骨架屏</a></p><p>📒 <a href="https://juejin.cn/post/7153255870447484936" target="_blank" rel="noopener noreferrer">刚插上网线，电脑怎么知道自己的IP是什么</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/n6IEF2OinYN3slJXqc_xgw" target="_blank" rel="noopener noreferrer">Redis 实现分布式锁的 7 种方案</a></p><p>📒 <a href="https://juejin.cn/post/6844904039608500237" target="_blank" rel="noopener noreferrer">Koa的洋葱中间件，Redux的中间件，Axios的拦截器让你迷惑吗？实现一个精简版的就彻底搞懂了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/khS0wkBzQe4Lxn7jHK_0vA" target="_blank" rel="noopener noreferrer">学习 Babel 插件，把 Vue2 语法自动转成 Vue3！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QgOslh1TwpU2cJubnNxYNw" target="_blank" rel="noopener noreferrer">如何编写神奇的「插件机制」，优化基于 Antd Table 封装表格的混乱代码</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/m8kCdY7ZSr1LmDEYYOWGFA" target="_blank" rel="noopener noreferrer">从龟速 11s 到闪电 1s，详解前端性能优化之首屏加载</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/9g8Ha2xu2MbhkYTO4SkehA" target="_blank" rel="noopener noreferrer">前端框架：性能与灵活性的取舍</a></p><p>⭐️ <a href="https://juejin.cn/post/7152708637817831432" target="_blank" rel="noopener noreferrer">【面试高频题】难度 1.5/5，多解法经典面试题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/METf8Ng6Qnsu1uWGTzan8g" target="_blank" rel="noopener noreferrer">React 中常见的 8 个错误，如何避免</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/5AnRvwmA-U76T52FR47w8Q" target="_blank" rel="noopener noreferrer">在撸 Vue 的 ⌘+K 唤起菜单库时，我学到了很多</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/SLouDICt3HABv_wh-sSqKw" target="_blank" rel="noopener noreferrer">Go 实战技巧：避免内存分配的小技巧</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[10月9日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月9日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月9日内容汇总"/>
        <updated>2022-10-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 看了 web.dev 的 631 篇博客，我总结了这些内容]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/tft9YCVBlrEdsmfsihaRxA" target="_blank" rel="noopener noreferrer">看了 web.dev 的 631 篇博客，我总结了这些内容</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Uu3EAWpRO9pSbg1F1DLa_w" target="_blank" rel="noopener noreferrer">Go开源库、大项目的公共包，是这么用建造者模式的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Npid7nvqo5u9Jch83I4V1w" target="_blank" rel="noopener noreferrer">【第2747期】Islands Architecture（上）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/W6JFmMx3qAVShwgt4F2iEA" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#13 Creating utility packages</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XLEIcEywjald9Df0hJYwYw" target="_blank" rel="noopener noreferrer">快速在你的vue/react应用中实现ssr(服务端渲染)</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/dN9G4Tnt9HgVqlNh73HNUQ" target="_blank" rel="noopener noreferrer">探究 Go 源码中 panic &amp; recover 有哪些坑</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/t-TUAzL0q0oK7HsDVQRNMw" target="_blank" rel="noopener noreferrer">抖音二面：为什么模块循环依赖不会死循环？CommonJS和ES Module的处理不同</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/epK_0yn_EPIWJjz9xmddcA" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#12 Project misorganization</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/wNBkC-X1FMPuHBX1P_DXbQ" target="_blank" rel="noopener noreferrer">Go 的 IO 流怎么并发？小技巧分享</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Vhd2xO4SqU9BxmTUO-2Gcg" target="_blank" rel="noopener noreferrer">构建 webpack5 知识体系【近万字总结】</a></p><p>📒 如何实现卡片滚动效果</p><p>实现一个横向卡片滚动的效果，有两个需求：</p><ul><li>需要有滚动条，这样可以支持有触摸板的设备（即不能通过 <code>overflow: hidden;</code> 加上 <code>transform: translateX();</code> 或者相对定位偏移实现）</li><li>还要提供左右切换的按钮，这样便于鼠标操作，同时点击需要过渡动画</li></ul><p>根据第一点就可以确定，滚动的实现是父容器设置 <code>overflow-x: auto;</code> 实现的。那怎么实现第二个需求呢？</p><p>观察一下 ahooks 的 <code>useInfiniteScroll</code> 源码，控制滚动的核心就是 <code>scrollTop</code>、<code>scrollHeight</code>、<code>clientHeight</code> 这几个参数：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">packages/hooks/src/useInfiniteScroll/index.tsx:81</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 滚动触发的回调函数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">scrollMethod</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> el </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getTargetElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">el</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> scrollTop </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getScrollTop</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">el</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">       </span><span class="token comment" style="color:#999988;font-style:italic">// 滚动的距离，该参数值可以动态修改</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> scrollHeight </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getScrollHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">el</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 滚动内容实际的高度，该参数值只读</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> clientHeight </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getClientHeight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">el</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 外部滚动容器的高度，该参数值只读</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">scrollHeight </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> scrollTop </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> clientHeight </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> threshold</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">loadMore</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 绑定滚动事件监听器</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">useEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">'scroll'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">loading </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> loadingMore</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">scrollMethod</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> target </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://github.com/alibaba/hooks/blob/master/packages/hooks/src/useInfiniteScroll/index.tsx" target="_blank" rel="noopener noreferrer">https://github.com/alibaba/hooks/blob/master/packages/hooks/src/useInfiniteScroll/index.tsx</a></p></blockquote><p>那么在卡片滚动的需求中，对应的参数值为 <code>scrollLeft</code>、<code>scrollWidth</code>、<code>clientWidth</code>。只要 <code>scrollLeft + clientWidth &lt; scrollWidth</code>，就可以继续向右滚动：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> useCallback</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useEffect</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useMemo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useRef</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useState </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> useMemorizedFn </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"ahooks"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> useCarouselScroll </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">HTMLElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  target</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  customWidth</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  target</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MutableRefObject</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  customWidth</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">enablePrev</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setEnablePrev</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">enableNext</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setEnableNext</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> scrollLeft</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> clientWidth</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> scrollWidth </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> threshold </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> customWidth </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> clientWidth</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 一次滚动的距离</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setEnablePrev</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">scrollLeft </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setEnableNext</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">scrollLeft </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> clientWidth </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> scrollWidth</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">prev</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">enablePrev</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">threshold </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> scrollLeft</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 可以滚动一屏的距离</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">scrollLeft </span><span class="token operator" style="color:#393A34">-=</span><span class="token plain"> threshold</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 滚动不足一屏距离</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">scrollLeft </span><span class="token operator" style="color:#393A34">-=</span><span class="token plain"> scrollLeft</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">setEnablePrev</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">setEnableNext</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">next</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">enableNext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">scrollLeft </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> clientWidth </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> threshold </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> scrollWidth</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 可以滚动一屏的距离</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">scrollLeft </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> threshold</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 滚动不足一屏距离</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">scrollLeft </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">scrollWidth </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> scrollLeft </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> clientWidth</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">setEnableNext</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">setEnablePrev</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    enablePrev</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    enableNext</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    prev</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useMemorizedFn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">prev</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    next</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useMemorizedFn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>过渡动画的实现就很简单了，一行 CSS 代码搞定：</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">scroll-behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> smooth</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Next.js prefetch 策略</p><p>很多全栈框架，例如 Next.js 都会做 prefetch 预加载 chunk。Next.js 提供了一个 <code>&lt;Link /&gt;</code> 组件，可以实现 client-side route transitions，同时这个 <code>&lt;Link /&gt;</code> 还具有 prefetch 功能：</p><blockquote><p>Any <code>&lt;Link /&gt;</code> that is in the viewport (initially or through scroll) will be preloaded. Prefetch can be disabled by passing <code>prefetch={false}</code>. When <code>prefetch</code> is set to <code>false</code>, prefetching will still occur on hover. Pages using Static Generation will preload <code>JSON</code> files with the data for faster page transitions. Prefetching is only enabled in production.</p></blockquote><p>参考一下 <code>&lt;Link /&gt;</code> 源码实现：</p><p><a href="https://github.com/vercel/next.js/blob/canary/packages/next/client/link.tsx#L205" target="_blank" rel="noopener noreferrer">https://github.com/vercel/next.js/blob/canary/packages/next/client/link.tsx#L205</a></p><p>📒 <a href="https://juejin.cn/post/7033400734746066957" target="_blank" rel="noopener noreferrer">【一库】yalc: 可能是最好的前端link调试方案（已经非常谦虚了）</a></p><p>📒 <a href="https://juejin.cn/post/7043068238539784206" target="_blank" rel="noopener noreferrer">使用antv/G2生态半年有感</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/nH0v9wYe64--1HT_QJcKag" target="_blank" rel="noopener noreferrer">Go：符号表是什么？如何使用？</a></p><p>📒 Dracula UI</p><p>刚开源，特点如下。</p><p>1、<strong>为黑暗模式而建</strong>。大多数模板都是使用浅色的，后来才改成深色的。深色主题不应该是一个事后的想法，它们应该是一个首要任务。</p><p>2、<strong>设计师友好</strong>。通过使用一个高度可配置的设计系统，加快原型设计阶段。通过利用精心制作的Figma文件，轻松进行合作。</p><p>3、<strong>友好的开发者体验</strong>。不用担心类名，只需使用 Visual Studio 的代码片段。你可以利用自动完成的优势，也可以从你的代码编辑器中直接访问整个文档。</p><p><a href="https://ui.draculatheme.com/" target="_blank" rel="noopener noreferrer">https://ui.draculatheme.com/</a></p><p>📒 React 18 快在哪</p><p>主要是 3 点。</p><p>1、由于 React 18 有 Automatic Batching，多个 setState 只会触发一次渲染，而在 18 之前，setState 几次就会渲染几次
2、React 18 引入了新的服务器渲染架构，会带来显著的性能提升，请检查你的框架是否支持
3、React 18 引入了用于把状态更新标记为可终端的 startTransition，虽然不能让页面变快，但如果用户在可中断的状态更新中点击，会让你的应用更具有响应性</p><p><a href="https://www.reddit.com/r/reactjs/comments/xmr9tg/comment/ippsuin/" target="_blank" rel="noopener noreferrer">https://www.reddit.com/r/reactjs/comments/xmr9tg/comment/ippsuin/</a></p><p>📒 再见 useEvent</p><p>useEvent 原计划解两个问题，1）渲染优化，2）useEffect 重新触发问题。但是发现没办法一下子做两件事。于是 useEvent RFC 废弃，这两个问题会拆开了来解。渲染优化问题倾向用 React Forgot 解，useEffect 重新触发问题会通过另一个专门解此问题的 RFC 来解，命名上应该不再会用 useEvent。</p><p><a href="https://github.com/reactjs/rfcs/pull/220#issuecomment-1259938816" target="_blank" rel="noopener noreferrer">https://github.com/reactjs/rfcs/pull/220#issuecomment-1259938816</a></p><p>📒 Umi x Valtio</p><p>Umi 在 4.0.23 中加入了 Valtio 插件。这是在大量调研之后，基于中台项目的场景做的决定，使用 Valtio 作为下一代的数据流。</p><p>为啥是 valtio？</p><p>valtio 的特点是外部多 Store + 基于 Proxy。1）个人用不惯 jotai 和 recoil 这种 react 内部原子化的数据流方案，感觉和被 redux 培养起来的心智模型有冲突，所以会更倾向于外部 Store 一些，2）由于场景是中后台，对于兼容性的容忍度比较高，比如不用兼容 IE11，所以完全可以用基于 Proxy 的数据流方案，这类数据流方案在更新数据和读取数据时都更简单。</p><p>为啥不是 zustand？</p><p>1、zustand 和 valtio 是同一个作者写的，功能覆盖上其实比较类似，最大的区别是 valtio 基于 proxy 而 zustand 不是。个人有几个方面的考虑，1）更新数据，2）读取数据，3）类型提示。</p><p>2、更新数据的方式更符合人性，比如可以直接 <code>state.todos['321'].completed = true</code>，而不用 <code>setState(todos =&gt; ({ …todos, 321: { …todos['321'], completed: true } }))</code>。当然，这一点非 proxy 方案可基于 immer 实现和 proxy 方案类似的操作。</p><p>3、读取数据默认高性能，无需 selector。非 proxy 方案比如 react-redux 和 zustand 为了性能优化，避免不必要的 re-render，通常会通过 selector 选择 store 的一部分，这会带来不必要的心智负担。基于 Proxy 的方案是响应式的，无需 selector，默认高性能。</p><p>4、类型提示的差异主要在扩展上。valtio 用的是组合式，zustand 用的是 middleware。没具体试过 zustand 的 middleware，但个人理解，理论上 middleware 的类型提示没有 valtio 友好。比如 valtio 的 proxyWithHistory 会把数据结构改成 <code>{ value, history, redo, undo, … }</code> 这种，在类型提示上可以完美衔接。</p><p><a href="https://umijs.org/docs/max/valtio" target="_blank" rel="noopener noreferrer">https://umijs.org/docs/max/valtio</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[10月2日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月2日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/10月2日内容汇总"/>
        <updated>2022-10-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 你写 Go 代码写注释吗？谈谈 Go 代码注释问题]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/5ZDzcGqenAvtOeSU-baV9A" target="_blank" rel="noopener noreferrer">你写 Go 代码写注释吗？谈谈 Go 代码注释问题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/eh7G_J3a0JudZRR-wrElag" target="_blank" rel="noopener noreferrer">程序员新人频繁使用count(*)，被组长批评后怒怼：性能并不拉垮！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hW5VcbjpFCoGOp3BPsnAZQ" target="_blank" rel="noopener noreferrer">【第2745期】React 可组合 API 的设计原则</a></p><p>📒 <a href="https://juejin.cn/post/7150668738990178312" target="_blank" rel="noopener noreferrer">推荐12个值得学习的TypeScript宝库！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3AVzctr8LwaFK9R_-x-uaA" target="_blank" rel="noopener noreferrer">【第2744期】更好的 React SSR</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hklnsSEmJG3Sgc6RezfJHA" target="_blank" rel="noopener noreferrer">Java19 正式 GA！虚拟线程性能炸裂！！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/GWHfDXbTpaXKmeZVQRtF2w" target="_blank" rel="noopener noreferrer">[<!-- -->翻译<!-- -->]<!-- -->Go 运行时的未来 Go Runtime: 4 years later</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/HJ9183I_suybZCT7Seg75A" target="_blank" rel="noopener noreferrer">我认为 Go 的成功归功于这 5 个方面</a></p><p>⭐️ <a href="https://juejin.cn/post/7147939014870302756" target="_blank" rel="noopener noreferrer">给想转Go或者Go进阶同学的一些建议</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Q-juege6Gn_H0xY4_OtR7Q" target="_blank" rel="noopener noreferrer">【第2742期】Remesh 介绍：用以开发大型复杂 Web App 的 DDD 框架</a></p><p>📒 Monorepo Handbook 新鲜出炉</p><p>TurboRepo 团队近日发布了 Monorepo 手册，包含关于 Monorepo 你需要知道的一切，并提供了详尽的配置示例，内容如下：</p><ul><li>什么是 Monorepo？</li><li>安装包 (npm、pnpm、Yarn 1、Yarn &gt;=2)</li><li>Workspaces 工作区</li><li>迁移到 Monorepo</li><li>任务编排</li><li>构建</li><li>Docker 部署</li><li>共享代码</li><li>Lint</li><li>测试</li><li>发布 (Changesets)</li><li>@manypkg/cli 处理包版本依赖</li></ul><p><a href="https://turborepo.org/docs/handbook/what-is-a-monorepo" target="_blank" rel="noopener noreferrer">https://turborepo.org/docs/handbook/what-is-a-monorepo</a></p><p>📒 <a href="https://juejin.cn/post/7147660762519961631" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 54 期：TS 4.9 Beta、Monorepo Handbook、第 92 次 TC39 会议、将 StoryBook Stories</a></p><p>📒 HTTPS 就一定安全？我不信</p><p>从客户端的角度看，其实并不知道网络中存在中间人服务器这个角色。</p><p>那么中间人就可以解开浏览器发起的 HTTPS 请求里的数据，也可以解开服务端响应给浏览器的 HTTPS 响应数据。相当于，中间人能够 “偷看” 浏览器与服务端之间的 HTTPS 请求和响应的数据。</p><p>但是要发生这种场景是有前提的，<strong>前提是用户点击接受了中间人服务器的证书</strong>。</p><p>中间人服务器与客户端在 TLS 握手过程中，实际上发送了自己伪造的证书给浏览器，而这个伪造的证书是能被浏览器（客户端）识别出是非法的，于是就会提醒用户该证书存在问题。</p><p>抓包工具 之所以可以明文看到 HTTPS 数据，工作原理与中间人一致的。</p><p>对于 HTTPS 连接来说，中间人要满足以下两点，才能实现真正的明文代理:</p><ul><li>中间人，作为客户端与真实服务端建立连接这一步不会有问题，因为服务端不会校验客户端的身份；</li><li>中间人，作为服务端与真实客户端建立连接，这里会有客户端信任服务端的问题，也就是服务端必须有对应域名的私钥；</li></ul><p>中间人要拿到私钥只能通过如下方式：</p><ul><li>去网站服务端拿到私钥；</li><li>去CA处拿域名签发私钥；</li><li>自己签发证书，且被浏览器信任；</li></ul><p>不用解释，抓包工具只能使用第三种方式取得中间人的身份。</p><p>使用抓包工具进行 HTTPS 抓包的时候，需要在客户端安装根证书，这里实际上起认证中心（CA）的作用。</p><p>我们要保证自己电脑的安全，不要被病毒乘虚而入，而且也不要点击任何证书非法的网站，这样 HTTPS 数据就不会被中间人截取到了。</p><p>当然，我们还可以通过 HTTPS 双向认证来避免这种问题。</p><p>一般我们的 HTTPS 是单向认证，客户端只会验证了服务端的身份，但是服务端并不会验证客户端的身份。</p><p>如果用了双向认证方式，不仅客户端会验证服务端的身份，而且服务端也会验证客户端的身份。</p><p><a href="https://mp.weixin.qq.com/s/nS1bMy2TejmGwEfCHPXy5A" target="_blank" rel="noopener noreferrer">HTTPS 就一定安全？我不信</a></p><p>📒 tauri 快速上手</p><p>快速上手 3 命令。</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> create tauri-app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> run tauri dev</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> run tauri build</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://blog.logrocket.com/tauri-electron-comparison-migration-guide/" target="_blank" rel="noopener noreferrer">https://blog.logrocket.com/tauri-electron-comparison-migration-guide/</a></p></blockquote><p>📒 新一波 JavaScript 框架</p><p>作者从 Web 之初、CGI、PHP 开始讲起，讲 JavaScript 历史画卷一幅幅展开，既有 Ajax、jQuery、Backbone、YUI 等一代代的 JavaScript 库前辈，又有 Astro、Fresh、Remix 等新一波的 JavaScript 框架。推荐阅读，从中可以了解为什么会有这些库和框架，以及他们都是为了解什么而生的？</p><p>所以，既然每个框架都会被历史所代替，前端开发者应该如何保持竞争力？</p><blockquote><p><a href="https://frontendmastery.com/posts/the-new-wave-of-javascript-web-frameworks/" target="_blank" rel="noopener noreferrer">https://frontendmastery.com/posts/the-new-wave-of-javascript-web-frameworks/</a></p></blockquote><p>📒 TypeScript 4.9 satisfies</p><p>satisfies 是 TypeScript 4.9 新引入的操作符，用于只做校验但不改变表达式的类型结果。通常用于 Object 声明，因为既需要保留每个属性的类型，又需要做 key 值校验。</p><p>比如，</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Colors</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'red'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'green'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'blue'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  red</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  green</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  blue</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'ok'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  black</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//~~~~~~~~~~ 既校验了 key，要求满足 Colors，这里的 black 会抛错</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> satisfies Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Colors</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">unknown</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 又让每个属性拥有完整类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">red</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">at</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">blue</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">startsWith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'o'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-beta/#the-satisfies-operator" target="_blank" rel="noopener noreferrer">https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-beta/#the-satisfies-operator</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/E4YJiDQbTapQGEfM8V0vJQ" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#11 Not using the functional options pattern</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QBNSh2yn0RA1lZBdHcgz8w" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 161 期</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[9月25日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月25日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月25日内容汇总"/>
        <updated>2022-09-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 前端也要懂算法，不会算法也能微调一个 NLP 预训练模型]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7146575333721341966" target="_blank" rel="noopener noreferrer">前端也要懂算法，不会算法也能微调一个 NLP 预训练模型</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yHB9BzEGIki1fyjYojdpYQ" target="_blank" rel="noopener noreferrer">Go 语言官方依赖注入工具 Wire 使用指北</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/niLk_n9Yp-iyl_RIie3Umw" target="_blank" rel="noopener noreferrer">超干货！彻底搞懂Golang内存管理和垃圾回收</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/MH9vjR9ZMWzqd5aoOAAnlg" target="_blank" rel="noopener noreferrer">好用的map-struct转换库 mergo</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/ZVLaykgYaOACbT2r-K0qBg" target="_blank" rel="noopener noreferrer">分享三个阅读 Go 源码的窍门</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/kkSQu7zdr6x_CZRE5uW-lg" target="_blank" rel="noopener noreferrer">聊聊分布式一致性！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ThVtw8TVuhxIyYxJy6sOWw" target="_blank" rel="noopener noreferrer">深入浅出带你走进Redis！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ocPx6Sw09ioDyz_IOWK69Q" target="_blank" rel="noopener noreferrer">工作中常见的 6 种设计模式，你用过几种</a></p><p>📒 基于 Next.js 和 tailwind.css 搭建博客</p><p><a href="https://tailwindcss.com/docs/typography-plugin#adding-custom-color-themes" target="_blank" rel="noopener noreferrer">https://tailwindcss.com/docs/typography-plugin#adding-custom-color-themes</a></p><p><a href="https://juejin.cn/post/7145119069216178212" target="_blank" rel="noopener noreferrer">使用 Next.js 和掘金 API 打造个性博客</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/WzAVtmFmEMhY-MiNEgQ0fw" target="_blank" rel="noopener noreferrer">如何保障 MySQL 和 Redis 的数据一致性</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/C4WNRM3fY2ezpE1qzjNhvA" target="_blank" rel="noopener noreferrer">electron-vite：新一代 Electron 开发利器，带你轻松玩转 Electron</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/eqIcLlh3a4TUwx3lk2qLYA" target="_blank" rel="noopener noreferrer">create-vite 原理揭秘</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/EMiEoq9HYTHi8TLEs7N8EQ" target="_blank" rel="noopener noreferrer">字节二面：Redis 的大 Key 对持久化有什么影响</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/VWEKgnOWVnufz5pfvRjUWw" target="_blank" rel="noopener noreferrer">美团三面：一直追问我， MySQL 幻读被彻底解决了吗</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/y1qHsQNR7EWeDU5g60Loqg" target="_blank" rel="noopener noreferrer">Go学设计模式--原型模式的考查点和使用推荐</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/sqq8PNBvhPDmD8T5W4h65g" target="_blank" rel="noopener noreferrer">使用viper实现yaml配置文件的合并</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/p_Ne6m5TC4oQCZ5_tZDWKA" target="_blank" rel="noopener noreferrer">「Go工具箱」一个简单、易用、安全的类型转换工具</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ydbuD9y8Uo-MZgOlxRZB0Q" target="_blank" rel="noopener noreferrer">探索组件在线预览和调试</a></p><p>📒 Golang 面试相关</p><p>LeetCode 刷题指南</p><p><a href="https://www.yuque.com/go-interview/set/xq5788" target="_blank" rel="noopener noreferrer">https://www.yuque.com/go-interview/set/xq5788</a></p><p>面试题库收集</p><p><a href="https://www.yuque.com/go-interview/set/interview-index" target="_blank" rel="noopener noreferrer">https://www.yuque.com/go-interview/set/interview-index</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/VKPSqS50Un29x30KIgB0tA" target="_blank" rel="noopener noreferrer">已入字节的大佬各厂三年Go面经</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Vl__2DCW7NBRf21y-FdNZw" target="_blank" rel="noopener noreferrer">掌握了这一招，Go的多版本管理不用愁</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QOxT81kOwJL2MPy1M1rbYw" target="_blank" rel="noopener noreferrer">react-spring 如何用旁路设计赋能前端交互</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ACP5BQIsJnBfno3O5eaK1g" target="_blank" rel="noopener noreferrer">解读 State of CSS 2022，让你早点下班的新特性</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/jHBbKUmF6Ka9nQwr5kqOAQ" target="_blank" rel="noopener noreferrer">从useEffect看React、Vue设计理念的不同</a></p><p>📒 <a href="https://juejin.cn/post/7145061375994724389" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 53 期：React Router 6.4、VS Code August 2022、2022 Google 谷歌开发者大会、Meta 开源</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Up9rUP6BW2BVCrksi52GDw" target="_blank" rel="noopener noreferrer">语雀桌面端技术架构实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/vg1hZo8lwIyhkoLSJ80uqg" target="_blank" rel="noopener noreferrer">package.json 配置完全解读</a></p><p>📒 函数组合</p><p>函数组合有很多场景，这篇文章介绍了如何把他用在 React 项目中，换一种代码组织方式，让代码更简洁、优雅和可扩展。</p><p>假如你有一个项目，项目里有这样的需求，1）检查用户登录状态，2）特性检测按需渲染，3）埋点日志需求，4）layout 渲染。你可能会这么写。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">App</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">user</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">isLogin</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">signIn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> pageName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> uid </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> user</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">isAdmin</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">AdminComponent</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> features</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">includes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'foo'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Foo</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Conent</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这里的 问题是，如果有多个组件都需要类似的逻辑，你可能就要复制粘贴了。解是用 Provider + HOC + Composition + Currying。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">withProviders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> showFooter</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Content</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>withProviders 如下。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">withProviders</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">compose</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    withUser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    withFeatures</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    withLogger</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">withLayout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>withLogger 如下。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">withLogger</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token maybe-class-name">WrappedComponent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> pageName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> uid </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">WrappedComponent</span><span class="token tag" style="color:#00009f"> </span><span class="token tag spread punctuation" style="color:#393A34">{</span><span class="token tag spread operator" style="color:#393A34">...</span><span class="token tag spread" style="color:#00009f">props</span><span class="token tag spread punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://medium.com/javascript-scene/why-every-react-developer-should-learn-function-composition-23f41d4db3b1" target="_blank" rel="noopener noreferrer">https://medium.com/javascript-scene/why-every-react-developer-should-learn-function-composition-23f41d4db3b1</a></p><p>📒 初级程序员 vs. 高级程序员</p><p>要分别初级程序员和高级程序员，其中一点是看他们关注的是「软件」还是「系统」。</p><p>初级工程师关心编写软件的问题。 他们重视代码质量，采用最佳实践，努力采用最先进的技术。他们在学习新技术方面投入了大量时间。对他们来说，最终的目标是创建优雅的、可执行的、可维护的软件。</p><p>高级工程师关心的是建立系统。 对他们来说，创建软件只是其中的一个步骤。首先，他们会质疑这个软件是否需要被建造。他们会问它能解决什么问题，为什么要解决这些问题。他们询问谁将会使用这个软件，在什么规模上使用。他们考虑软件将在哪里运行，以及他们将如何监测它是否正常工作。他们还决定如何衡量该软件是否真正解决了它应该解决的问题。</p><p><a href="https://codewithstyle.info/software-vs-systems/" target="_blank" rel="noopener noreferrer">https://codewithstyle.info/software-vs-systems/</a></p><p>📒 React Router 6.4</p><p>React Router 发布 6.4，大量新功能，包括数据加载/突变/重新验证、错误/中断/竞争条件处理以及支持 Suspense 的加载/骨架 UI 等。</p><p>1、路由创建方式变更，之前用 BrowserRouter + Routes，现在改用 createBrowserRouter 创建路由和 RouterProvider 渲染路由。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">RouterProvider</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">router</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript function" style="color:#d73a49">createBrowserRouter</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">[</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">  </span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f"> path</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'/'</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"> element</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript tag punctuation" style="color:#393A34">&lt;</span><span class="token tag script language-javascript tag class-name" style="color:#00009f">Root</span><span class="token tag script language-javascript tag" style="color:#00009f"> </span><span class="token tag script language-javascript tag punctuation" style="color:#393A34">/&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f"></span><span class="token tag script language-javascript punctuation" style="color:#393A34">]</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>2、路由级的数据流，基于 loader + action + Form，在路由配置中声明 loader 和 action，然后如下使用即可。</p><p>处理数据加载。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 声明数据</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">loader</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用数据</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">useLoaderData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>处理数据提交。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 使用定制表单元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 处理表单提交</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">action</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>3、延迟数据加载方案，基于 defer + useAsyncValue/Await。由于考虑到 CLS（Content Layout Shift），默认没有做延迟数据加载，开发者可以手动开启。用哪种方式其实是需要权衡的，各有利弊。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 1、loader 里延迟返回</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">loader</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">defer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> count</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2、渲染时用 Await 延迟渲染，不阻塞 Suspense 的瀑布流</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Await</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">resolve</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">data</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">count</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">errorElement</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript tag punctuation" style="color:#393A34">&lt;</span><span class="token tag script language-javascript tag" style="color:#00009f">p</span><span class="token tag script language-javascript tag punctuation" style="color:#393A34">&gt;</span><span class="token tag script language-javascript plain-text" style="color:#00009f">error load count</span><span class="token tag script language-javascript tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag script language-javascript tag" style="color:#00009f">p</span><span class="token tag script language-javascript tag punctuation" style="color:#393A34">&gt;</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">p</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">p</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Await</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>4、ScrollRestoration 可以模拟浏览器在加载器完成后位置变化时的滚动恢复，以确保滚动位置恢复到正确的位置，甚至跨域。</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">ScrollRestoration</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/XqFh2K3KXVu-845MPmKrTg" target="_blank" rel="noopener noreferrer">Go 代码风格没人喜欢？不对，Gofmt 是所有人的最爱...</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/MgOyG99mUvOTlsxQVQZGUw" target="_blank" rel="noopener noreferrer">程序里对象很深很大，可以用这个设计模式缓解一下</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/kd-8GT5zDU1OrqncPyD1cw" target="_blank" rel="noopener noreferrer">「Go工具箱」推荐一个变量调试神器：go-spew</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2OYeWCCCkJWR4eIedU9s7Q" target="_blank" rel="noopener noreferrer">【第2734期】JavaScript &amp; Node.js 的测试最佳实践 - 第二章：后端测试</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/wcuW0wsJ00La_3Q1dgDLqw" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 160 期 — 竟然这么多人不理解 map 的 make 含义</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3XEYWsK1TcvYvMYDzbMETA" target="_blank" rel="noopener noreferrer">简单的 redis get 为什么也会有秒级的延迟</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/LZVYsjY5Wbg5m4JhOjtfoQ" target="_blank" rel="noopener noreferrer">golang net/url 路径穿越漏洞</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[9月18日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月18日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月18日内容汇总"/>
        <updated>2022-09-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Babel 插件：30分钟从入门到实战]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7143921535445631012" target="_blank" rel="noopener noreferrer">Babel 插件：30分钟从入门到实战</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/QBZ1dp0XIqMo24vVFYf1fA" target="_blank" rel="noopener noreferrer">全面解读！Golang中泛型的使用</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/LwGuTBV6-hk1T5URW8dTgg" target="_blank" rel="noopener noreferrer">Umi4.0多页签设计</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/OobHbsVbBEM8kiIIts8P_w" target="_blank" rel="noopener noreferrer">V8 是如何执行 JavaScript 代码的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/e3bL1i6WT-4MwK-SEpUa6Q" target="_blank" rel="noopener noreferrer">「Go工具箱」推荐一个非常简单的深拷贝工具：deepcopy</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-685DKQuzTEbsg0pZzQSVg" target="_blank" rel="noopener noreferrer">ECMAScript 2023将新增的9个数组方法</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/BPFJSkvv_UPMux0dSZuh-A" target="_blank" rel="noopener noreferrer">关于 React Re-Render</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/qFSzt32BjFW_Gl5OpI3lXA" target="_blank" rel="noopener noreferrer">Go：基于 Redis 实现的延迟队列详解</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/k0eYoJuL0JO_tHEiU887wA" target="_blank" rel="noopener noreferrer">这个帮你理清Go程序调用栈的工具，1.17以上可用</a></p><p>📒 <a href="https://juejin.cn/post/7127161983622725639" target="_blank" rel="noopener noreferrer">一起来实现一个Antd Form</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/vzSbdOFrwpA2U0JpMx_nsw" target="_blank" rel="noopener noreferrer">如何检测 JavaScript 原生函数是否被打过 "猴子补丁"</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/56tth8PSquB1eR5-1XaDWA" target="_blank" rel="noopener noreferrer">鹅厂后台大佬教你Go内存管理！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/VKpHtRVIJh669SLz2nUJuQ" target="_blank" rel="noopener noreferrer">Plasmo Framework：次世代的浏览器插件开发框架</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/NkSyv7iDSZsLhMUgAi-r4w" target="_blank" rel="noopener noreferrer">不得不知道的Golang之sync.Map解读！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/_sZiClAyq1MDrh7XoIgSBQ" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 52 期：Babel 7.19.0、Fresh 1.1、React为什么重新渲染、新的 Web 性能指标</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/kn7cHvZvjR93V0CW06e0NQ" target="_blank" rel="noopener noreferrer">我被骂了，但我学会了如何构造高性能的树状结构</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/tfZ5zHo8FG_Rc1JteLBS7g" target="_blank" rel="noopener noreferrer">「Go工具箱」一个将非负整数转换成唯一、无序ID的工具：hashids</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/URJC9ERPrcniiFinUsIJkg" target="_blank" rel="noopener noreferrer">【图书】程序员的底层思维</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/iTFj1Sn5vPTgkAT2Q9YC0w" target="_blank" rel="noopener noreferrer">作为大厂面试官，原来这种学生最吃香！</a></p><p>📒 Why Storybook in 2022</p><blockquote><p><a href="https://storybook.js.org/blog/why-storybook-in-2022/" target="_blank" rel="noopener noreferrer">https://storybook.js.org/blog/why-storybook-in-2022/</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/59x3uElLaSZVf77itv8B3Q" target="_blank" rel="noopener noreferrer">如何像gitlab-runner那样将Go应用安装为系统服务</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/8JPj9Rz5xyrnAloeno0RNA" target="_blank" rel="noopener noreferrer">React Router v6 完全指南</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/81L1RRiCdqGMJmk-iUZldg" target="_blank" rel="noopener noreferrer">【第2726期】开发模式 "Development Mode" 是如何工作的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/FdCl0BZT_v_pjBZKcTUnoQ" target="_blank" rel="noopener noreferrer">你信吗？Go 泛型竟然已经被迅速采用</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/jzCfXs6jz820XOHksZzBDA" target="_blank" rel="noopener noreferrer">做一个不崩溃的核酸系统到底有多难</a></p><p>📒 <a href="https://juejin.cn/post/7142371499255529509" target="_blank" rel="noopener noreferrer">写给前端仔的自动化测试入门小作文</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/MN4wsITSVYHNMPoFRpRZFQ" target="_blank" rel="noopener noreferrer">「Go工具箱」一个兼具单机和集群模式的轻量级限流器：throttled</a></p><p>📒 CSR 最佳实践</p><p>随着 Next.js 和 Remix 的流行，SSR 看似已成为 React 社区的首选。但如果你用 SSR 是为了性能和 SEO，那可能可以重新考虑下，因为 CSR 也能做到。</p><p>关于性能。</p><p>1、减少尺寸。1）少用依赖，2）选择轻量级的依赖，比如用 day.js 代替 moment，用 zustand 代替 redux toolkit。</p><p>2、缓存。利用 webpack 的 cacheGroups 设置，提取依赖，当依赖没有变更时，hash 值不变，提高缓存利用率。推荐配置如下，让每个依赖拥有单独的文件和 hash，这样单个依赖变更时不会影响其他依赖。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token literal-property property" style="color:#36acaa">optimization</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">runtimeChunk</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'single'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">splitChunks</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">chunks</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'initial'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">cacheGroups</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">vendor</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">test</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex" style="color:#36acaa">[\\/]node_modules[\\/]</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 加这句可以避免异步 chunk 的 vendor 重复问题，比如 a 和 b 都依赖 moment，不加这句 moment 会被打两遍而不是被提取出来</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">chunk</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'all'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 让每个依赖拥有单独的文件和 hash</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function-variable function" style="color:#d73a49">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> context </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">match</span><span class="token punctuation" style="color:#393A34">(</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex" style="color:#36acaa">[\\/]node_modules[\\/](.*?)([\\/]|$)</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>3、Code Splitting。通常有两种，1）基于路由的 Code Splitting，当用户访问页面 A 时无需加载页面 B、C、D 的脚本，2）大依赖 Code Splitting，让整体页面更快出来，让大依赖的部分不影响页面渲染速度。</p><p>4、预加载异步 Chunk。主要避免出现下图中最后一个资源文件的瀑布流现象，思路是生成和路由对应的 assets 表，然后在 HTML 最前面加入「匹配路由生成 link preload 标签」的脚本。</p><p>5、生成静态数据。在 build 阶段从 CMD 或服务器上把数据拉下来，存成 json 或其他格式，用户请求时就只需从本地读取即可，访问本地或就近的 CDN 肯定比访问远程服务器更快。如果要重新生成数据，重新跑 build 或者重新执行脚本就好。</p><p>6、预加载数据。这和「4」类似，4 预加载的是 JS，这里需要预加载数据。做法也和「4」类似，把数据请求和路由做关联，然后运行时「匹配路由生成针对数据请求的 link preload 标签」。</p><p>7、预加载其他页面的数据。当 hover（desktop）或进入 viewport（mobile）时，做的对应 Link 的 preload as fetch。</p><p>8、避免序列化的渲染。比如一个应用有 Nav 导航 + 主内容，是应该先出导航再出主内容，还是应该导航和主内容都好了之后一起出？作者觉得应该是后者，实现方法是通过调整 Suspense 元素的位置。这一点其实我是有疑问的，我觉得前一种渲染方式也挺好，避免长时间的白屏。</p><p>9、Transition 切换页面（依赖 React 18）。当我们切换页面时，有两个选择。1）切过去，等 loading，渲染；2）等 loading，切过去+渲染。基于 React 18 的 useTransition 可以实现后者，代码如下。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> n </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useNavigate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">startTransition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">n</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">to</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>10、预加载异步页面。作者介绍了个方法，把 React.lazy 封一下，在 window load 事件之后延迟自动执行。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">lazyPrefetch</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token parameter">chunk</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'load'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">chunk</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">once</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">lazy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">chunk</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>11、Module Federation。</p><p><a href="https://github.com/theninthsky/client-side-rendering" target="_blank" rel="noopener noreferrer">https://github.com/theninthsky/client-side-rendering</a></p><p>📒 人手 10x 工程师</p><p>先看两种 10x 工程师。1）写 10x 代码的工程师，但这类工程师对于负责 Review 他代码的同学会很有挑战，2）能评估复杂问题，站在技术前沿，先人一步拿出优雅解决方案的工程师，这类工程师一个团队通常没有几个。</p><p>你可能会觉得这两种都比较遥远，别灰心，还有一种 10x 工程师。他关注开发体验（dx）和团队健康，关注小但有倍增效应的事。比如添加缓存以加快持续集成，比如定期修复项目 setup 说明，比如增加 precommit 或加快自动化测试后让故障发生在本地而不是 CI 环境。这些变化随着时间推移所产生的累积效应，虽然不是你自己做了 10x 的工作，但通过提高一群工程师的生产力也能达到 10x 提效。</p><p><a href="https://typeofnan.dev/10x-engineering-for-the-rest-of-us/" target="_blank" rel="noopener noreferrer">https://typeofnan.dev/10x-engineering-for-the-rest-of-us/</a></p><p>📒 开源相关</p><ul><li>Next.js 发布 12.3，Fast Refresh 支持 .env 和 tsconfig.json，检测到 ts 或 tsx 文件自动完成 TypeScript 配置、SWC Minifier Stable</li><li>Meta 开源 shumai，基于 Bun + Flashlight 的 JavaScript 机器学习库</li><li>module-federation/nextjs-mf，让 Next.js 支持 Module Federation，目前 CSR Only</li><li>gradejs/gradejs，GradeJS 无需源码即可分析生产阶段的 webpack 产物构成，包括潜在问题，依赖了哪些包，等等</li></ul><p>📒 <a href="https://mp.weixin.qq.com/s/rPDGgAlzNrTqZX74zzqDsA" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 159 期 — 这道题目有点意思</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[9月11日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月11日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月11日内容汇总"/>
        <updated>2022-09-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 CSS 如何实现文本换行]]></summary>
        <content type="html"><![CDATA[<p>📒 CSS 如何实现文本换行</p><p>在开发的时候遇到一个问题，后端给的文本包含换行符 <code>/n</code>，前端如何实现换行展示。最开始以为只能通过富文本展示，但实际上 CSS 中有一个属性可以支持换行：</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">white-space</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> pre-wrap</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/white-space" target="_blank" rel="noopener noreferrer">https://developer.mozilla.org/zh-CN/docs/Web/CSS/white-space</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/QkDUQOx9w1HZIFyyvIzp-A" target="_blank" rel="noopener noreferrer">Go 生态：Prometheus的四种指标类型，我终于搞懂了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ShH-SWhTCQLYasoIHy3xWg" target="_blank" rel="noopener noreferrer">Go 语言创始人：复制亿点点代码比用别人轮子好！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fNcsMQuO1z8nmIRuiC8VnQ" target="_blank" rel="noopener noreferrer">「Go工具箱」推荐一个实现进度条功能的工具：uiprogress</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JVGttsilTXLThaonU6ME6A" target="_blank" rel="noopener noreferrer">给蚂蚁金服antv提个PR，以为是改个错别字，未曾想背后的原因竟如此复杂！</a></p><p>📒 前端相关文章汇总</p><p><a href="https://medium.com/@bytefer" target="_blank" rel="noopener noreferrer">https://medium.com/@bytefer</a></p><p><a href="https://medium.com/pixel-and-ink/a-peek-at-userequest-hook-ba960cbddbf8" target="_blank" rel="noopener noreferrer">https://medium.com/pixel-and-ink/a-peek-at-userequest-hook-ba960cbddbf8</a></p><p><a href="https://javascript.plainenglish.io/15-utility-types-that-every-typescript-developer-should-know-6cf121d4047c" target="_blank" rel="noopener noreferrer">https://javascript.plainenglish.io/15-utility-types-that-every-typescript-developer-should-know-6cf121d4047c</a></p><p><a href="https://blog.bitsrc.io/6-best-ways-to-create-a-new-react-application-57b17e5d331a" target="_blank" rel="noopener noreferrer">https://blog.bitsrc.io/6-best-ways-to-create-a-new-react-application-57b17e5d331a</a></p><p>📒 Golang 技术方案</p><p><a href="https://kms.netease.com/topics/topic/612/item/14727" target="_blank" rel="noopener noreferrer">https://kms.netease.com/topics/topic/612/item/14727</a></p><p><a href="https://kms.netease.com/article/27452#%E9%80%89%E5%9E%8B" target="_blank" rel="noopener noreferrer">https://kms.netease.com/article/27452#%E9%80%89%E5%9E%8B</a></p><p><a href="https://github.com/NetEase-Media/ngo" target="_blank" rel="noopener noreferrer">https://github.com/NetEase-Media/ngo</a></p><p>📒 依赖注入简介</p><blockquote><p><a href="https://blog.codeminer42.com/dependency-injection-in-js-ts-part-1/" target="_blank" rel="noopener noreferrer">https://blog.codeminer42.com/dependency-injection-in-js-ts-part-1/</a></p></blockquote><p>📒 JavaScript 模块中的默认导出很糟糕吗</p><blockquote><p><a href="https://www.lloydatkinson.net/posts/2022/default-exports-in-javascript-modules-are-terrible/" target="_blank" rel="noopener noreferrer">https://www.lloydatkinson.net/posts/2022/default-exports-in-javascript-modules-are-terrible/</a></p></blockquote><p>📒 VS Code 发布新版本</p><p>保持上下文的 "粘性滚动"不再是一个实验性功能。将与 TypeScript v4.8 一起发布。</p><blockquote><p><a href="https://code.visualstudio.com/updates/v1_71" target="_blank" rel="noopener noreferrer">https://code.visualstudio.com/updates/v1_71</a></p></blockquote><p>📒 使用 gRPC 构建安全 API</p><p>一个允许两个 Node 应用程序通过 HTTP/2 和基于协议缓冲区的 gRPC 机制进行通信的演练教程。</p><blockquote><p><a href="https://snyk.io/blog/building-a-secure-api-with-grpc/" target="_blank" rel="noopener noreferrer">https://snyk.io/blog/building-a-secure-api-with-grpc/</a></p></blockquote><p>📒 最小化依赖关系的四种方法</p><p>在接连不断的供应链事故（和漏洞），或者查看了 <code>node_modules</code> 文件夹的最终体积后，你可能会想要将依赖关系保持在最低限度。这篇文章介绍了一些方法。</p><blockquote><p><a href="https://blog.appsignal.com/2022/08/31/4-ways-to-minimize-your-dependencies-in-nodejs.html" target="_blank" rel="noopener noreferrer">https://blog.appsignal.com/2022/08/31/4-ways-to-minimize-your-dependencies-in-nodejs.html</a></p></blockquote><p>📒 安装并运行 <code>bin</code> 脚本</p><p>npm 包可以通过 package.json 的 <code>bin</code> 属性指定它们提供的 shell 脚本和可运行文件。Axel 深入研究了它的工作原理，并且提供了两种方式来安装提供此类脚本的软件包。</p><blockquote><p><a href="https://2ality.com/2022/08/installing-nodejs-bin-scripts.html" target="_blank" rel="noopener noreferrer">https://2ality.com/2022/08/installing-nodejs-bin-scripts.html</a></p></blockquote><p>📒 Create Rust App: 用一行命令开启现代 Rust + React Web 应用程序</p><p>如果你想用 Rust 构建应用程序的后端，那么该库提供了一种 CRA 式的体验。它使用 Vite 并且新增了 SQLite 支持。</p><blockquote><p><a href="https://github.com/Wulf/create-rust-app" target="_blank" rel="noopener noreferrer">https://github.com/Wulf/create-rust-app</a></p></blockquote><p>📒 何时使用 <code>useLayoutEffect</code> 而不是 <code>useEffect</code></p><p>你的 UI 渲染过程中有烦人的闪烁吗？可能是你错误使用了其中之一的 Hook : 这与 Hook 是在浏览器绘制之前还是之后触发有关。</p><blockquote><p><a href="https://javascript.plainenglish.io/react-hooks-when-to-use-uselayouteffect-instead-of-useeffect-3271a96d881a?gi=622ccbf807f3" target="_blank" rel="noopener noreferrer">https://javascript.plainenglish.io/react-hooks-when-to-use-uselayouteffect-instead-of-useeffect-3271a96d881a?gi=622ccbf807f3</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/b805ZIO7-IabjStlAs7Wow" target="_blank" rel="noopener noreferrer">美团二面：考我幻读，结果答的不好</a></p><p>📒 码住！Golang并发安全与引用传递总结</p><p>先看一个在Go中关于Map类型并发读写的经典例子：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> testMap  </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">go</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token boolean" style="color:#36acaa">_</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> testMap</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"bar"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">go</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      testMap</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"bar"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"foo"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">select</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>以上例子会引发一个Fatal error：</p><blockquote><p>fatal error: concurrent map read and map write</p></blockquote><p>产生这个错误的原因就是在Go中Map类型并不是并发安全的，出于安全的考虑，此时会引发一个致命错误以保证程序不出现数据的混乱。</p><p>Golang 如何检测 Map 并发异常？</p><p>对于查询操作，大致检查并发错误的流程如下：在查询前检查并发flag是否存在，如果存在就抛出异常。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> h</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flags</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">hashWriting </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">throw</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"concurrent map read and map write"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>对于修改操作则如下：</p><ul><li>写入前检查一次标记位，通过后打上标记</li><li>写入完成再次检查标记位，通过后还原标记</li></ul><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//各类前置操作</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> h</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flags</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">amp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">hashWriting </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//检查是否存在并发</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">throw</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"concurrent map writes"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//赋值标记位</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">h</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flags </span><span class="token operator" style="color:#393A34">^=</span><span class="token plain"> hashWriting</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//后续操作</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">done</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//完成修改后，再次检查标记位</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> h</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flags</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">hashWriting </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">throw</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"concurrent map writes"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//还原标记位取消hashWriting标记</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">h</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flags </span><span class="token operator" style="color:#393A34">&amp;^=</span><span class="token plain"> hashWriting</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如何避免 Map 的并发问题？</p><p>go官方认为因为Map并发的问题在实际开发中并不常见，如果把Map原生设计成并发安全的会带来巨大的性能开销。因此需要使用额外方式来实现。</p><ol><li>自行使用锁和map来解决并发问题</li></ol><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> cocurrentMap </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  sync</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">RWMutex</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  m </span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> testMap </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">cocurrentMap</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">:</span><span class="token function" style="color:#d73a49">make</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//写</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  testMap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Lock</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  testMap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"a"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"foo"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  testMap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Unlock</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//读</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  testMap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">RLock</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">testMap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"a"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  testMap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">RUnlock</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>这个方法存在问题就是并发量巨大的时候，锁的竞争也会带来巨量消耗，性能一般</p></blockquote><ol start="2"><li>使用sync.Map</li></ol><p>sync.Map通过巧妙的设计来提高并发安全下Map的性能，其设计思路是通过空间换时间来实现的，同时维护2份数据，read&amp;dirty。read主要用来避免读写冲突。</p><p>其数据结构如下：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Map </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  mu Mutex </span><span class="token comment" style="color:#999988;font-style:italic">//锁</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  read atomic</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Value </span><span class="token comment" style="color:#999988;font-style:italic">//readOnly</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  dirty </span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">interface</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">entry </span><span class="token comment" style="color:#999988;font-style:italic">//*entry</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  misses </span><span class="token builtin">int</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> readOnly </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  m       </span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">interface</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">entry</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  amended </span><span class="token builtin">bool</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// true if the dirty map contains some key not in m.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> entry </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  p unsafe</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Pointer </span><span class="token comment" style="color:#999988;font-style:italic">// *interface{}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>使用示例如下：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> m sync</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Map</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 写</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Store</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"test"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Store</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 读</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">val1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">_</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Load</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"test"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">val2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">_</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Load</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">bool</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//遍历</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value </span><span class="token keyword" style="color:#00009f">interface</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">bool</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic">//....</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//删除</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"test"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//读取或写入</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">LoadOrStore</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"test"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这里对sync.Map的原理不做深入展开，只提几点特性：</p><ul><li>read和dirty是共享内存的，尽量减少冗余内存的开销</li><li>read是原子性的，可以并发读，写需要加锁</li><li>读的时候先read中取，如果没有则会尝试去dirty中读取（需要有标记位readOnly.amended配合）</li><li>dirty就是原生Map类型，需要配合各类锁读写</li><li>当read中miss次数等于dirty长度时，dirty会提升为read，并且清理已经删除的k-v（延迟更新，具体如何清理需要enrty中的p标记位配合）</li><li>双检查（在加锁后会再次对值检查一遍是否依然符合条件）</li><li>sync.Map适用于读多写少的场景</li><li>sync.Map没有提供获取长度size的方法，需要通过遍历来计算</li></ul><p>切片类型 Slice 是并发安全的吗</p><p>与Map一样，Slice也不是并发安全的。但是在切片中并不会引发panic，如果程序无意中对切片使用了并发读写，严重的话会导致获取的数据和之后存储的数据错乱，所以这里要格外小心，可以通过加锁来避免。</p><p>切片除了并发有问题外，还有几点注意：</p><ul><li>Go只会对基础值类型在传参中使用深拷贝，实际上对于Slice和Map类型，使用的是浅拷贝，Slice作为传参，其指向的内存地址依然是原数据</li><li>Slice扩容机制的影响：向Slice中添加元素超出容量的时候，我们知道会触发扩容机制，而扩容机制会创建一份新的【原数据】此时，它与浅拷贝获取到的变量是没有任何关联的</li></ul><p><a href="https://mp.weixin.qq.com/s/dZIcI_3b8N8a2_nzJ7fNOA" target="_blank" rel="noopener noreferrer">码住！Golang并发安全与引用传递总结</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/U6FjIdGZ3n13-pS2J7nvLQ" target="_blank" rel="noopener noreferrer">ES6你用过哪些惊艳的写法</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/rJN14WFRTKjhoy8oWPulWw" target="_blank" rel="noopener noreferrer">用代码画时序图！YYDS</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/VQsKA1nQ6leh60d_JXJg_g" target="_blank" rel="noopener noreferrer">面试官：mysql查询 limit 1000,10 和limit 10 速度一样快吗</a></p><p>📒 <a href="https://snyk.io/blog/best-practices-to-build-java-containers-with-docker/" target="_blank" rel="noopener noreferrer">10 best practices to build a Java container with Docker</a></p><p>📒 <a href="https://linuxhandbook.com/create-systemd-services/" target="_blank" rel="noopener noreferrer">How to create a systemd service in Linux</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/r2_eSoM11nZPYp_1aNatBQ" target="_blank" rel="noopener noreferrer">Go 1.19.1 和 Go 1.18.6 终究还是来了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/oVr9ojK6A8d8DIiIVdHwpQ" target="_blank" rel="noopener noreferrer">5分钟自建数据库可视化平台，在线管理数据库也太方便了！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/tVASa1trXkJR9nK_isTbmw" target="_blank" rel="noopener noreferrer">匿名 iframe：COEP 的福音！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/nzpJPMVs1JznYotZXb4tbQ" target="_blank" rel="noopener noreferrer">这些强大的 JS 操作符，你都知道吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/605zrHjHFsjJvRq7_xFP_Q" target="_blank" rel="noopener noreferrer">「Go工具箱」一个基于双向链表实现的LRU缓存工具</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mNjLiEBnHIZhOTrDwNkmvA" target="_blank" rel="noopener noreferrer">这个 Go 开发的网络抓包工具，不仅好用还支持ES检索</a></p><p>📒 <a href="https://juejin.cn/post/7134583899597832200" target="_blank" rel="noopener noreferrer">一道简单又有意思的 JavaScript 手写题 — 异步加法 asyncAdd</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/naGheZq_z5d8pyB_i9hY7g" target="_blank" rel="noopener noreferrer">高并发下的网络 IO 模型设计</a></p><p>📒 <a href="https://juejin.cn/post/7096047543447978014" target="_blank" rel="noopener noreferrer">qiankun微前端改造实战（架构设计+代码实现）-超级详细vue代码干货篇！（伸手党福利）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/FE8WgfINZ0hSWldkXVGo9g" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#8 any says nothing</a></p><p>📒 <a href="https://juejin.cn/post/7140549209735823373" target="_blank" rel="noopener noreferrer">读 Node.js 源码深入理解 cjs 模块系统</a></p><p>📒 当 React Query 遇见 React Router</p><p>React Router 6.4 即将正式发布，React Router 也加入了远程状态管理的数据获取游戏。本文将带你了解 React Router 和现有的远程状态管理库(如：React Query)之间的竞争和关联，作者认为他们是天造地设的一对。</p><p><a href="https://beta.reactrouter.com/en/dev" target="_blank" rel="noopener noreferrer">https://beta.reactrouter.com/en/dev</a></p><p><a href="https://tkdodo.eu/blog/react-query-meets-react-router" target="_blank" rel="noopener noreferrer">https://tkdodo.eu/blog/react-query-meets-react-router</a></p><p>隔壁家 Vue Router 的数据获取相关提案 Vue Router Data Loaders。</p><p><a href="https://github.com/vuejs/rfcs/discussions/460" target="_blank" rel="noopener noreferrer">https://github.com/vuejs/rfcs/discussions/460</a></p><p>📒 重新思考流行的 Node.js 模式和工具</p><p>Node.js 最佳实践、JavaScript 和 Node.js 测试最佳实践 的作者 Yoni Goldberg 对 Node.js 中的流行工具发出了灵魂拷问，并给出了他的思考：</p><ul><li><code>Node-convict</code> 比 <code>Dotenv</code> 更好；</li><li>从 Controller 调用 Service 时，要尽量抽象 Service 的内容(多用心封装封装)，尽可能屏蔽掉技术细节和复杂性，让看你代码的同学赏心悦目一些；</li><li>Nest.js 中万物皆可依赖注入，但简单点也许世界会更美好；</li><li>不一定要用 <code>Passport.js</code>；</li><li><code>SuperTest</code> 的三合一语法有时候并没有那么好用；</li><li><code>Fastify</code> 装饰器错误姿势</li><li>catch 子句的正确姿势；</li><li>避免重复使用日志工具 <code>Morgan</code>；</li><li>减少使用 process.env.NODE_ENV 当作判断条件。</li></ul><p><a href="https://practica.dev/blog/popular-nodejs-pattern-and-tools-to-reconsider/" target="_blank" rel="noopener noreferrer">https://practica.dev/blog/popular-nodejs-pattern-and-tools-to-reconsider/</a></p><p>📒 8 月登陆网络平台的新内容</p><p>Firefox 104、Chrome 104、Chrome 105 发布稳定版本。</p><ul><li>Chrome 104 新增 <strong>CSS transform 属性单独定义</strong></li><li>Chrome 104 新增 <strong>媒体查询的新语法</strong>，支持比较运算符，更加符合人体工程学</li><li>Chrome 105 新增 <strong>容器查询和 :has()</strong>，响应式的最佳拍档</li><li>Chrome 105 新增 <strong>Sanitizer API</strong>，防止 XSS 攻击的灭菌武器</li><li>Chrome 105 新增 <strong>:modal 伪类</strong></li><li>Firefox 104 支持 <strong>The findLast() 和 findLastIndex()</strong></li></ul><p><a href="https://web.dev/web-platform-08-2022/" target="_blank" rel="noopener noreferrer">https://web.dev/web-platform-08-2022/</a></p><p>📒 pnpm v7.10.0</p><p>Time-based 依赖解析模式</p><ol><li>直接依赖将安装其最低版本，比如 foo@^1.1.0，将会安装 1.1.0</li><li>间接依赖只会安装被选中的直接依赖在其发布时间点之前的版本</li></ol><p>据作者说，这种模式是为了减少供应链攻击导致项目“噶”的风险，因为它能保证间接依赖不会比直接依赖更加新。这样如果间接依赖被攻击，也不会安装被攻击的版本。不过这种解析模式需要拿到 npm 的完整元数据，所以速度会很慢。解法是自建 Verdaccio，并将 registry-supports-time-field 设置为 true。</p><p>能减少供应链攻击的风险是好事，但是感觉这种模式本身存在很多问题，比如不遵守 semver 语义，虽然社区里很多项目都没有好好遵守 :)、或者当旧的间接依赖修复了某个 bug，但是有 bug 的版本还是会被安装。</p><p><a href="https://github.com/pnpm/pnpm/releases/tag/v7.10.0" target="_blank" rel="noopener noreferrer">https://github.com/pnpm/pnpm/releases/tag/v7.10.0</a></p><p>📒 <a href="https://juejin.cn/post/7140216695834017822" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 51 期：pnpm v7.10.0、8 月登陆网络平台的新内容、重新思考流行的 Node.js 模式和工具、打包 JavaScript 库的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1tUkWA1Df6k1lX8q5PW17g" target="_blank" rel="noopener noreferrer">从Vuex到Pinia</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-PGp9meVMBGlkss7dXqDXA" target="_blank" rel="noopener noreferrer">程序员有很厉害，不外传的代码吗？可以运行，但不能动的那种！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/NjX2be78BlHrXF5hlKlA8A" target="_blank" rel="noopener noreferrer">你想知道的前后端协作规范都在这了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hZiRxXUrQwWEwT9JBkllTg" target="_blank" rel="noopener noreferrer">1.3w字，一文详解死锁！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/rAwplRSzwZne_KaCAJ2omA" target="_blank" rel="noopener noreferrer">【第2724期】前后端数据接口协作提效实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Rn4QjAmi581R0WkDxyTLjQ" target="_blank" rel="noopener noreferrer">去字节面试，直接让人出门左拐：Bean 生命周期都不知道！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/q7xK94mOphCO9PWVhsBIQQ" target="_blank" rel="noopener noreferrer">聊聊数据库建表的15个小技巧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/nDg3NGAoeLdHkm54kb5bWw" target="_blank" rel="noopener noreferrer">如何优化你的 Node.js API</a></p><p>📒 <a href="https://juejin.cn/post/7139768397423706126" target="_blank" rel="noopener noreferrer">金九银十Go面试题进阶知识点：select和channel</a></p><p>📒 禁用 Cookie 后会怎样</p><p>会报错！解法很简单也很粗暴，就是加 try…catch。</p><p><a href="https://blog.tomayac.com/2022/08/30/things-not-available-when-someone-blocks-all-cookies/" target="_blank" rel="noopener noreferrer">https://blog.tomayac.com/2022/08/30/things-not-available-when-someone-blocks-all-cookies/</a></p><p>📒 现代 JS 库打包</p><p>这是一篇关于如何打包 JavaScript 库的现代化指南，介绍了维护 JavaScript 库的一些基础知识和最佳实践，推荐作为入门阅读。</p><p><a href="https://github.com/frehner/modern-guide-to-packaging-js-library" target="_blank" rel="noopener noreferrer">https://github.com/frehner/modern-guide-to-packaging-js-library</a></p><p>📒 Error Boundary 指南</p><p>虽然理想情况下是在生产之前捕获错误，但有些错误是会躲过测试的，比如网络错误，而如果没有正确处理，这些错误会导致 React 声明周期崩溃，导致白屏，并最终影响你的用户。正确的方式是提供适当的视觉反馈和潜在的行动指引（例如：重试机制）来优雅的处理这些错误。</p><p>你可能会有几个疑问。1）为啥会白屏？因为从 React 16 开始，没有被捕获的错误将导致整个 React 组件树的卸载。2）为啥 try.catch 不行？因为 React Hooks 执行是异步的，捕获不了。</p><p>解法当然就是用 React 官方提供的 Error Boundary 了，通过 Error Boundary 把组件包起来，可以想象成是包了一层 try…catch，组件报错会到此为止，不会再往上报。一个简单的 ErrorBoundary 如下。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ErrorBoundarySimple</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Component</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">hasError</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">componentDidCatch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">error</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> unknown</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// report the error to your favorite Error Tracking tool (ex: Sentry, Bugsnag)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getDerivedStateFromError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">error</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> unknown</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Update state so the next render will show the fallback UI.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">hasError</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">hasError</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">p</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token maybe-class-name">Failed</span><span class="token plain"> to fetch users</span><span class="token punctuation" style="color:#393A34">.</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">p</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">children</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>但是官方的 Error Boundary 其实有缺陷，他不支持以下场景的报错，包括 Event handlers、异步代码比如 setTimeout 或 requestAnimationFrame 回调、SSR、Error Boundary 自己抛的错。同时，我们可能还需要提供重试机制等行动指南。解法是用 react-error-boundary 这个库。</p><p>react-error-boundary 如何支持重试？他提供的 ErrorBoundary 组件可以配置 FallbackComponent 组件，而这个组件有 error 和 resetErrorBoundary 两个 props，后者用于重试。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ErrorBoundary</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-error-boundary'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">ErrorFallback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> error</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> resetErrorBoundary </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">pre</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">message</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">pre</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">button onClick</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">resetErrorBoundary</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">retry</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">button</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">App</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">ErrorBoundary</span><span class="token plain"> </span><span class="token maybe-class-name">FallbackComponent</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token maybe-class-name">ErrorFallback</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">Users</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">ErrorBoundary</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>react-error-boundary 如何捕获 React 生命周期外的错误？比如 Event Handler 和异步代码。react-error-boundary 提供 useErrorHander hook，他会返回处理错误的函数。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> useErrorHandler </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-error-boundary'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">App</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> handleError </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useErrorHandler</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleSubmit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">xxx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token spread operator" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">e</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// do render</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://meticulous.ai/blog/react-error-boundaries-complete-guide/" target="_blank" rel="noopener noreferrer">https://meticulous.ai/blog/react-error-boundaries-complete-guide/</a></p><p>📒 10 个 React 新手陷阱</p><p>React 是 unopinionated 的，同样的问题会存在许多不同的解法，这给开发者留下了大量的空间来用自己愚蠢的想法把事情搞砸。在今天的文章中，我们将看看 React 中的 10 个陷阱（反模式），以及改进我们代码的技巧和窍门，同时也可以为前端技术面试做准备。</p><p>1、巨型组件。就是一个组件内很大，通常是因为不知道如何组织代码，或者不想把时间浪费在组织代码上。这样的组件很难理解、重构和测试。通过 WebStorm 的「Refactor - Move」或者 VSCode 的 Glean 插件快速提速代码到文件，可以节省你不少时间。</p><p>2、嵌套陷阱。不要在组件内定义子组件，比如 <code>function Parent() { const Child = () =&gt; &lt;div&gt;Child&lt;/div&gt;; return &lt;&gt;&lt;Child /&gt;&lt;/&gt; }</code>，解法是把 Child 定义提到外面。</p><p>3、没有用 useMemo/useCallback。遇到重计算的点，每次 re-render 会重新执行导致性能消耗严重，比如 <code>const total = expensiveCal(count)</code>。解法是用 useMemo 避免重复计算，比如 <code>const total = useMemo(() =&gt; expensiveCal(count), [count])</code>。如果遇到函数，记得切换到 useCallback。</p><p>4、无意义的 div 元素。React 组件只能由一个根组件，当需要渲染多个相邻的元素时，你可能会引入 div 元素。但这不是必要的，不必要的 div 元素可能导致可访问性和 CSS 样式问题。更好的做法是用 Fragment 组件，比如 <code>&lt;&gt;&lt;Foo /&gt;&lt;Bar /&gt;&lt;/&gt;</code>。</p><p>5、混乱的文件。随着组件越来越多，在一个文件中导出多个组件是「诱人」的。但是这样，也会很快让事情变得复杂。更好的做法是有一套自己的文件组织规范，比如一个组件一个文件，或者一个组件一个文件夹，同时在文件夹下可能还会有自己的测试文件等。</p><p>6、巨大的 Bundle 产物。大型复杂应用的最大问题之一就是产物很大，这会让页面加载变慢，因为浏览器需要很长时间来下载、解析和执行 JavaScript Bundle 产物。解法是应用内置了 code splitting 功能的框架，或者使用 Suepense + React.lazy + import()。</p><p>7、Prop Drilling。当上层组件中持有 state，而一个深度嵌套的组件需要使用这个 state 时，一种做法是用 props 透过中间组件一层层往下传，而实际上中间组件并不需要他们，这就是 Prop Drilling。解法是用 Redux 或其他数据流工具，或者使用 Context。</p><p>剩下 3 个是 Prop Plowing、Try Some Curry 和 Code Smarter，感觉不太重要，是为了凑 10 个加的，我就不介绍了，有兴趣的可以查看原文。</p><p><a href="https://medium.com/@imranfarooq0306/10-react-traps-to-avoid-as-react-developer-5570808e346b" target="_blank" rel="noopener noreferrer">https://medium.com/@imranfarooq0306/10-react-traps-to-avoid-as-react-developer-5570808e346b</a></p><p>📒 useMemo + useCallback</p><p>这是一篇很好的 useMemo 和 useCallback 入门文章，但没有引入啥新知识，我就不展开了。</p><p><a href="https://www.joshwcomeau.com/react/usememo-and-usecallback/" target="_blank" rel="noopener noreferrer">https://www.joshwcomeau.com/react/usememo-and-usecallback/</a></p><p>📒 React 18 SSR 流式渲染</p><p>React 18 SSR 流式渲染可基于 Suspense + Lazy、renderToPipeableStream 和 hydrateRoot 实现。Suspense + Lazy 在客户端用于代码拆分和懒加载，在服务端则用于流式渲染，renderToPipeableStream 用于流式返回数据，hydrateRoot 用于在流式返回后就开始注水而无需等到全部内容都返回。</p><p>以上完成了流式渲染，但还有个问题需要解，即「数据怎么获得」？并且需要同时考虑服务端和客户端。作者给的解是还处于实验阶段的 Data Fetching API。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> resource </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetchProfileData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Posts</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> posts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> resource</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">posts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// render with posts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>目前要支持 Data Fetching API，可将 Promise 包装成 Data Fetching API。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">wrapPromise</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> status </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'pending'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> suspensder </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">r</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    status </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'success'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">e</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      status </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'error'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">status </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'pending'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">throw</span><span class="token plain"> suspensder</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">status </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'error'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">throw</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">status </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'success'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Suspense 识别 Data Fetching 的 loading 状态是基于 read 方法的返回值。如果 throw promise 即还在 loading，如果 throw error 则出错，如果返回数据则完成 loading。</p><p><a href="https://juejin.cn/post/7137976587047141407" target="_blank" rel="noopener noreferrer">在 React 18 下，如何实现产品级的 SSR 和流式渲染</a></p><p>📒 开源推荐</p><p><strong>1. clean-pkg-json</strong></p><p>NPM 发包时不需要的 package.json 字段</p><p><a href="https://github.com/privatenumber/clean-pkg-json" target="_blank" rel="noopener noreferrer">https://github.com/privatenumber/clean-pkg-json</a></p><p><strong>2. ts-prune</strong></p><p>用于找到 TypeScript 项目未使用的 export 信息，消除 dead code</p><p><a href="https://github.com/nadeesha/ts-prune" target="_blank" rel="noopener noreferrer">https://github.com/nadeesha/ts-prune</a></p><p><strong>3. module-federation/typescript</strong></p><p>Typescript Types Support For Module Federation</p><p><a href="https://github.com/module-federation/typescript" target="_blank" rel="noopener noreferrer">https://github.com/module-federation/typescript</a></p><p><strong>4. React Router 6.4 将于下周发布</strong></p><p>📒 Go 眼中的文件系统是什么？ io.FS</p><p>Go 理解的文件系统，只要能实现一个 Open 方法，返回一个 File 的 interface ，这个 File 只需要实现 Stat，Read，Close 方法即可。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 文件系统的接口</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> FS </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">File</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 文件的接口</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> File </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Stat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">FileInfo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">byte</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Close</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>有没有发现，OS 的 FS 已经满足了条件。所以，Go 的 FS 可以是 OS 的 FS ，自然也可以是其他的实现。</p><p>Go 在此 io.FS 的基础上，再去扩展接口，增加文件系统的功能。比如，加个 ReadDir 就是一个有读目录的文件系统 ReadDirFS ：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> ReadDirFS </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  FS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 读目录</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">ReadDir</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">DirEntry</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>以上是 Golang 接口继承的写法，<code>ReadDirFS</code> 接口继承了 <code>FS</code> 接口，同时扩展了 <code>ReadDir</code> 方法。注意，Golang 是不支持面向对象的。</p></div></div><p>加个 Glob 方法，就成为一个具备路径通配符查询的文件系统：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> GlobFS </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  FS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 路径通配符的功能</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Glob</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pattern </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>加个 Stat ，就变成一个路径查询的文件系统：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> StatFS </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  FS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 查询某个路径的文件信息</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Stat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">FileInfo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这些非常经典的文件系统的定义 Go 在 io/fs 里面已经做好了。</p><p>我们的目标是实现一个 Go 的 FS ，这个定义已经在 io.FS 有了。我们只需要写一个结构体，实现它的方法，那么你就可以说这是一个 FS 了。</p><p>这里其实就可以有非常多的想象空间，比如，可以是 OS 的 FS，也可以是 memory FS ，hash FS 等等。网上有不少例子。但其实标准库已经有一个最好的例子，那就是 embed FS 。</p><p>我们来看下 embed 怎么实现一个内嵌的文件系统。embed 的实现在 embed/embed.go 这个文件中，非常精简。</p><p>首先，在 embed package 里定义了一个结构体 FS ，这个结构体将是 io.FS 的具体实现。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 作为具体 FS 的实现</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> FS </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  files </span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">file</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 代表一个内嵌文件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> file </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  data </span><span class="token builtin">string</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 文件的数据全在内存里</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  hash </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">16</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">byte</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// truncated SHA256 hash</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>embed 里面的 FS 结构体只需要实现 Open 这个方法即可：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Open 的具体实现</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f FS</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">File</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 通过名字匹配查找到 file 对象</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  file </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">lookup</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 如果没找到</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> file </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">PathError</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Op</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"open"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Err</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ErrNotExist</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 如果是目录结构</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> file</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">IsDir</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">openDir</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">file</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">readDir</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 找到了就封装成 openFile 结构体</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">openFile</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">file</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>上面的 Open ，如果是文件的化，返回的是一个 openFile 的结构体 ，作为 io.File 接口的具体实现：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 代表一个文件的实现</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> openFile </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  f </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">file </span><span class="token comment" style="color:#999988;font-style:italic">// the file itself</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  offset </span><span class="token builtin">int64</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// current read offset</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">openFile</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Close</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain">               </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">openFile</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Stat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">FileInfo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">openFile</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">b </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">byte</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 判断偏移是否符合预期</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">int64</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> io</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">EOF</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">PathError</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Op</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"read"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Err</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ErrInvalid</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 从内存拷贝数据</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  n </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">copy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  f</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">offset </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">int64</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> n</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如上，只需要实现 Read，Stat，Close 方法即可。这就是一个完整的、Go 层面的 FS 的实现。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>Go 的 FS 封装有啥用呢</p><ul><li>单测方便了，可以直接对应用进行测试，不必依赖底层实现</li><li>封装出一个 io.FS 的抽象，意图和 OS 的 FS 解耦，类似 embed FS 这种非 OS 文件系统的需求，可以有方法扩展了</li></ul></div></div><p><a href="https://mp.weixin.qq.com/s/bZO6kfhfdMaOkYZuGjOl_Q" target="_blank" rel="noopener noreferrer">Go 眼中的文件系统是什么？ io.FS</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/5CFjXV8dI_Pczl5g2z95jA" target="_blank" rel="noopener noreferrer">对 Go2 错误处理提案的批判</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/n2zLsJun0go4dR3g1Pi84Q" target="_blank" rel="noopener noreferrer">微服务配置中心， 这个方案 Go 里用起来不输 SpringCloud</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/lo59WvtOoqdA87dn9DiraQ" target="_blank" rel="noopener noreferrer">Go语言爱好者周刊：第 158 期</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[9月4日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月4日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/9月4日内容汇总"/>
        <updated>2022-09-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Resize Observer 介绍及原理浅析]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/o41_hJE6Sa67b3GtK3ogIA" target="_blank" rel="noopener noreferrer">Resize Observer 介绍及原理浅析</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/kiLgCwfbak6CXHJWxomSeA" target="_blank" rel="noopener noreferrer">【第2722期】腾讯医药微信小程序性能优化：从0.9秒到0.5秒</a></p><p>📒 <a href="https://juejin.cn/post/7138781839720153096" target="_blank" rel="noopener noreferrer">深入理解 Mocha 测试框架：从零实现一个 Mocha</a></p><p>📒 <a href="https://juejin.cn/post/7128369638794231839" target="_blank" rel="noopener noreferrer">React 官网为什么那么快</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/xjY0d8eNTmAuCZKxKQeu7g" target="_blank" rel="noopener noreferrer">基于storybook组件库的技术选型该怎么选</a></p><p>📒 图解 Node.js 的核心 event-loop</p><p>我们平时说 Node.js 是单线程仅仅是指 node 执行我们的 JS 代码，更准确地说是 V8 执行 JS code 是发生在单线程里面的。实际上如果你打开 Node 进程，会发现它有不少 worker thread。这是一个典型的单进程多线程模型。这些 worker thread 被放置于线程池里面，而 V8 执行 JS code 的线程被称为主线程。</p><p><a href="https://mp.weixin.qq.com/s/kz9ahljqVnJ7m6PExULs6A" target="_blank" rel="noopener noreferrer">图解 Node.js 的核心 event-loop</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/xAi8IuD1GrfS7qiJqQqM3Q" target="_blank" rel="noopener noreferrer">手把手教你手写 Vite Server（二）—— 插件架构设计</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/SLy0e1HnEcMFlB__jRuu3A" target="_blank" rel="noopener noreferrer">为什么 Vue3 的 VNode 不能单独组成一棵完整的树</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/LJ4zVn31UeM7Z1ouN67t8A" target="_blank" rel="noopener noreferrer">深度解读 Vite 的依赖扫描</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/HzT6G9x6fb4hPZqkBvTIew" target="_blank" rel="noopener noreferrer">浅谈MyBatis批量插入的3种方法，10w条数据使用foreach仅需2秒！！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zLNwq32UKaCsaAXn2BaZkw" target="_blank" rel="noopener noreferrer">「Go工具箱」重磅推荐：一个国产的，star高达12k+的操作excel的包：Excelize</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zT4d2snbG8td8fg9Gt--ig" target="_blank" rel="noopener noreferrer">拒绝 Go 代码臃肿，其实在这几块可以用下观察者模式</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3VrteSGHNKO5qRjNYTuj5g" target="_blank" rel="noopener noreferrer">几个非常有意思的javascript知识点总结</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/nDnQuZn3hVgrwqWVada2cw" target="_blank" rel="noopener noreferrer">AI数字绘画 stable-diffusion 保姆级教程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Ucqqg4h9uRo7RVd8XCz80w" target="_blank" rel="noopener noreferrer">Go 的零值有什么用？看看这 4 个场景</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/5TfAoS6nuFalfZuQ2Fv3_w" target="_blank" rel="noopener noreferrer">对前端架构的理解 - 分层与抽象</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/uAh_9gIth2HNS67y2z8pew" target="_blank" rel="noopener noreferrer">【第2719期】如何使用 HTTPS 进行本地开发</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/xDXwsVjOfU2j3gisiHTZTQ" target="_blank" rel="noopener noreferrer">Go 适合 IO 密集型？并不准确！</a></p><p>📒 <a href="https://dev.to/lubomirblazekcz/announcing-vituum-template-engines-and-more-in-vite-377k" target="_blank" rel="noopener noreferrer">Announcing Vituum - Template engines and more in Vite</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Y3NGQH3hrT85O7aN7IrCIQ" target="_blank" rel="noopener noreferrer">「Go工具箱」一个让终端内容彩色化的工具：Color</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fzmN6zFVioQGedTdSDmyqQ" target="_blank" rel="noopener noreferrer">如何让 Go 反射变快</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DG48sC4b42TEpHLNnFtlhw" target="_blank" rel="noopener noreferrer">MySQL 单表最大两千万？我不信</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/12BS4V6fvXkeb84XDpPnHw" target="_blank" rel="noopener noreferrer">了解微前端，深入前端架构的前世今生</a></p><p>📒 <a href="https://oscarotero.com/deno/" target="_blank" rel="noopener noreferrer">Deno cheat sheet</a></p><p>🌛 <a href="https://github.com/TheAlgorithms/Rust" target="_blank" rel="noopener noreferrer">用 Rust 实现的数据结构与算法合辑</a></p><p>📒 使用 React 18 和 Suspense 改善 INP（Interaction to Next Paint）指标</p><blockquote><p><a href="https://vercel.com/blog/improving-interaction-to-next-paint-with-react-18-and-suspense" target="_blank" rel="noopener noreferrer">https://vercel.com/blog/improving-interaction-to-next-paint-with-react-18-and-suspense</a></p></blockquote><p>📒 7 种创建新 React 应用的最佳方式</p><p>Create React App 可能是最有名的，但还有其他一些方法值得考虑，包括更大的框架（如 Next.js）或构建系统（如 NX）。</p><blockquote><p><a href="https://blog.bitsrc.io/6-best-ways-to-create-a-new-react-application-57b17e5d331a?gi=dc52c656ac21" target="_blank" rel="noopener noreferrer">https://blog.bitsrc.io/6-best-ways-to-create-a-new-react-application-57b17e5d331a?gi=dc52c656ac21</a></p></blockquote><p>📒 Advanced React component composition</p><blockquote><p><a href="https://frontendmastery.com/posts/advanced-react-component-composition-guide/" target="_blank" rel="noopener noreferrer">https://frontendmastery.com/posts/advanced-react-component-composition-guide/</a></p></blockquote><p>📒 Why React Re-Renders</p><p>如果你想要使 React 应用获得最好的性能，那么理解和正确处理渲染过程是非常重要的。有很多关于如何使 React 渲染更高效的文章，但这篇文章深入探讨了为什么 React 能够以一种可访问的、容易遵循的方式进行渲染。</p><blockquote><p><a href="https://www.joshwcomeau.com/react/why-react-re-renders/" target="_blank" rel="noopener noreferrer">https://www.joshwcomeau.com/react/why-react-re-renders/</a></p></blockquote><p><code>why-did-you-render</code> 是一个经典的工具，用于进一步深入这个问题。</p><blockquote><p><a href="https://github.com/welldone-software/why-did-you-render" target="_blank" rel="noopener noreferrer">https://github.com/welldone-software/why-did-you-render</a></p></blockquote><p>⭐️ <a href="https://mp.weixin.qq.com/s/MlC6-TDf06LGpF8hxcSV_w" target="_blank" rel="noopener noreferrer">工厂模式有三个Level，你能用Go写到第几层</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/tu5bBNn3UJ5r3Z7K5eqwJw" target="_blank" rel="noopener noreferrer">TypeScript 4.8 发布！重点新特性解读</a></p><p>📒 React + TypeScript 最小知识集</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">HTMLAttributes</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">PropsWithChildren</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">HelloProps</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">HTMLAttributes</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name">HTMLDivElement</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">Hello</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FC</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">PropsWithChildren</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">HelloProps</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  children</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">rest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag spread punctuation" style="color:#393A34">{</span><span class="token tag spread operator" style="color:#393A34">...</span><span class="token tag spread" style="color:#00009f">rest</span><span class="token tag spread punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">Hello, </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">!</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">children</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li><code>React.FC</code> 表示 Function Component 函数式组件</li><li><code>PropsWithChildren</code> 让 <code>props.children</code> 带类型</li><li><code>HTMLAttributes&lt;HTMLDivElement&gt;</code> 让 <code>props</code> 可以使用 html 属性比如 <code>className</code></li></ul><p><a href="https://ente.io/blog/tech/typescript-for-react/" target="_blank" rel="noopener noreferrer">https://ente.io/blog/tech/typescript-for-react/</a></p><p>📒 Tauri vs. Electron</p><p>作者分别用 Tauri 和 Electron 实现了 Authme，然后从打包、启动时间、性能、后端、应用渲染、安全、自动更新、开发体验共 8 个维度进行了对比。</p><p>1、「打包」Tauri 完胜。1）尺寸上 Tauri 2.5M vs. Electron 85M，2）Tauri 的产物是二进制的，反编译解码逻辑所需成本相比 Electron 会高很多。
2、「启动时间」Tauri 胜。Tauri 2s vs. Electron 4s。
3、「性能」Tauri 完胜。
4、「后端」Electron 胜。因为 Electron 后端基于 Node，而 Tauri 基于 Rust。当然如果你会 Rust 则是另一回事。另外，Tauri 的 Roadmap 里有支持其他后端绑定的计划，比如 Deno，届时就又可以用 JavaScript/TypeScript 写后端了。
5、「应用渲染」Electron 胜。Electron 使用 Chromium，所以你的用户在 Windows、Linux 和 macOS 上看到的东西是一样的。Tauri 使用系统的 WebView，Windows 上使用 Edge Webview2（Chromium），Linux 上使用 WebKitGTK，macOS 上使用 WebKit。这里的问题是 Webkit 的支持总是落后一点，所以你可能会需要额外的补丁。
6、「安全」Tauri 胜。Tauri 内置大量安全功能，可以明确启用或禁用某些 API。Electron 中则可以完全访问 Node 的 API，所以相比来说更容易被黑客利用。
7、「自动更新」Electron 胜。Tauri 和 Electron 都内置了自动更新器，而 Tauri 的相对简单，同时需要维护依赖并手动更新 JSON，而 Electron 可基于 electron-updater 并直接从 Github 发布的二进制文件中提取，要方便很多。
8、「开发体验」Tauri 胜。基于 Tauri CLI 就会包含热重载、为所有平台构建你的应用程序、生成应用程序图标等全部功能，而 Electron 啥都没有提供，只有框架本身。</p><p><a href="https://www.levminer.com/blog/tauri-vs-electron" target="_blank" rel="noopener noreferrer">https://www.levminer.com/blog/tauri-vs-electron</a></p><p>📒 father 4 正式发布</p><p>father 4 的具备如下核心特性：</p><ul><li><strong>双模式构建</strong>： 支持 Bundless 及 Bundle 两种构建模式，ESModule 及 CommonJS 产物使用 Bundless 模式，UMD 产物使用 Bundle 模式</li><li><strong>多构建核心</strong>： Bundle 模式使用 Webpack 作为构建核心，Bundless 模式使用 esbuild 及 Babel 两种构建核心，可通过配置自由切换</li><li><strong>类型生成</strong>： 无论是源码构建还是依赖预打包，都支持为 TypeScript 模块生成 .d.ts 类型定义</li><li><strong>项目体检</strong>： 对 NPM 包研发常见误区做检查，让每一次发布都更加稳健</li><li><strong>微生成器</strong>： 为项目追加生成常见的工程化能力，例如使用 jest 编写测试</li><li><strong>依赖预打包</strong>： 开箱即用的依赖预打包能力，帮助 Node.js 框架/库提升稳定性、不受上游依赖更新影响（实验性）</li></ul><p>📒 <a href="https://mp.weixin.qq.com/s/Zb5zGOy_mdalUQ_Qy0HngQ" target="_blank" rel="noopener noreferrer">3种方式！Go Error处理最佳实践</a></p><p>📒 <a href="https://juejin.cn/post/7121244973558661150" target="_blank" rel="noopener noreferrer">超大体量项目，微前端落地方案，看完后悔来找我</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mxGv7IdQ_KcYqja5ffhmcQ" target="_blank" rel="noopener noreferrer">快速搭建 SpringCloud Alibaba Nacos 配置中心！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/xqhMG-bB71MoIQ9R_I48gw" target="_blank" rel="noopener noreferrer">k8s下微前端如何做金丝雀发布</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[8月28日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月28日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月28日内容汇总"/>
        <updated>2022-08-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 【第2714期】从Multirepo到Monorepo 袋鼠云数栈前端研发效率提升探索之路]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/JWks8VyuXoB5zaeYdyJPxw" target="_blank" rel="noopener noreferrer">【第2714期】从Multirepo到Monorepo 袋鼠云数栈前端研发效率提升探索之路</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fjeF3LLoGsPIQN4D3el67g" target="_blank" rel="noopener noreferrer">抖音平台多产物代码隔离技术的实践与探索</a></p><p>📒 <a href="https://juejin.cn/post/7123961170188304391" target="_blank" rel="noopener noreferrer">Hooks时代，如何写出高质量的react和vue组件</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/IGaUcYDIb4e3zGGi9jvdig" target="_blank" rel="noopener noreferrer">Vite 约定式路由的最佳实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2VGeRphTiS2XXUiBnhvvcA" target="_blank" rel="noopener noreferrer">Go使用泛型后，这么写单元测试会失效</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mO819q_r9qLVuRBE8cjx1Q" target="_blank" rel="noopener noreferrer">如何保证数据库和缓存双写一致性</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/fymuGPW-9agEtxYX2s4FPQ" target="_blank" rel="noopener noreferrer">【第2713期】工程化思维：主题切换架构</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Cq-CF1BC4PWwGnlRp4HrnQ" target="_blank" rel="noopener noreferrer">为了拿捏 Redis 数据结构，我画了 40 张图（完整版）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XmsSgGop7TT_RQvXyp1kGA" target="_blank" rel="noopener noreferrer">美团一面：如何在 100 亿数据中找到中位数</a></p><p>📒 解决老工程 toast 组件问题</p><p>老工程 React 15.x，Webpack 2.x，工程里面原先没有组件库。</p><p>关于 npm 包可能存在部分 ES6 语法，低版本 Webpack 无法解析问题，可以用 Babel 转一下。同理 NPM 包使用了 ES Module 模块语法，也可以用 Babel 转为 CommonJS。现在主要的问题是，大多数 toast 组件，底层都用了 React Hooks，即使 ES 语法兼容，但是运行环境 React 版本太老还是无法兼容。最终还是选用 rc-notification，参考 antd 封装：</p><p><a href="https://github.com/react-component/notification/tree/2.0.6" target="_blank" rel="noopener noreferrer">https://github.com/react-component/notification/tree/2.0.6</a></p><p><a href="https://github.com/ant-design/ant-design/blob/2.13.14/components/message/index.tsx" target="_blank" rel="noopener noreferrer">https://github.com/ant-design/ant-design/blob/2.13.14/components/message/index.tsx</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Q0vxASPNiACd_gCl-rq-2Q" target="_blank" rel="noopener noreferrer">Kubernetes原理与架构初探</a></p><p>📒 VS Code 1.70 新特性</p><p><strong>3-way merge editor</strong></p><p>三路合并编辑器是在1.69版本里上线的，这个功能允许用户在VS Code内快速解决 Git 合并冲突。该功能启用后，可以通过点击「源代码控制视图」中的冲突文件来打开合并编辑器。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">settings.json</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"git.mergeEditor"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>Git 提交辅助操作</strong></p><p>可以使用 <code>git.postCommitCommand</code> 来设置控制辅助操作，比如允许用户在提交信息后进行推送或者同步。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">settings.json</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"git.postCommitCommand"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sync"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>分支保护</strong></p><p>在之前的1.68版本中，VS Code就添加了 <code>git.branchProtection</code> 以用于配置受保护的特定分支。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">settings.json</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"git.branchProtection"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"main"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>Command Center</strong></p><p>Command Center 功能启用后，其位于编辑器顶部的长条空间，让用户可以快速搜索项目中的文件。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">settings.json</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"window.commandCenter"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>sticky scroll</strong></p><p>当用户在编辑器中滚动鼠标查看代码时，每个子模块（比如：类/接口/命名空间/函数/方法等等）代码的第一行会置顶固定住，以方便查看。</p><p>这对于一些长代码模块（比如一个很长的函数）的阅读体验提升还是非常有帮助的。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">settings.json</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"editor.experimental.stickyScroll.enabled"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/Mj_47WqUfIpcLF_-t38HYw" target="_blank" rel="noopener noreferrer">Java中的语法糖甜不甜？巧用枚举实现订单状态转换！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/EGN7G8ku-zkaZuzfBwx9Qw" target="_blank" rel="noopener noreferrer">看 Go 中的 struct 如何被优化，还有小插曲</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/7A6VCvuv8umUlOUzB2uHfA" target="_blank" rel="noopener noreferrer">Rust 与 Go 可以互操作</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/8Bc9k880DpwsaY9pJIowSA" target="_blank" rel="noopener noreferrer">SWC 入门介绍</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DbTAUiBt4GE4whYe9S6Ifw" target="_blank" rel="noopener noreferrer">听说TCP能保证不丢包？图解TCP六大丢包场景</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Z29mNvpU6LVBBSS9FGZk_w" target="_blank" rel="noopener noreferrer">Vue3中defineEmits、defineProps 是怎么做到不用引入就能直接用的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/gaOzwCypQMFAJ4X50aUOcg" target="_blank" rel="noopener noreferrer">浅析神经网络 Neural Networks</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Qlqt1pP_Li-PxOICrz7bAw" target="_blank" rel="noopener noreferrer">在 Go 里用 CGO？这 7 个问题你要关注！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/La5qCJh5Vup_gZIgZMOo4g" target="_blank" rel="noopener noreferrer">分布式接口幂等性、分布式限流：Guava 、nginx和lua限流</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Am0ORd08GsMc4xSdLG9kgg" target="_blank" rel="noopener noreferrer">Go 探讨了 13 年，怎么解决再赋值的坑</a></p><p>📒 TypeScript Collections</p><p>用 TypeScript 编写的数据结构合集</p><p><a href="https://github.com/basarat/typescript-collections" target="_blank" rel="noopener noreferrer">https://github.com/basarat/typescript-collections</a></p><p>📒 Vite Rollup Plugins</p><p>Vite3 中使用 Rollup 插件的兼容性列表</p><p><a href="https://github.com/patak-dev/vite-rollup-plugins" target="_blank" rel="noopener noreferrer">https://github.com/patak-dev/vite-rollup-plugins</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/VFS4TWi3OpeAegScZ4cJRw" target="_blank" rel="noopener noreferrer">Go语言从0到1实现最简单的数据库！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/IRGAN0e9tbL5hwG4hx1kxQ" target="_blank" rel="noopener noreferrer">一文读懂TypeScript类型兼容性</a></p><p>📒 Communicating Effectively As A Tech Lead</p><p>Addy Osmani 的新作，从 Simplify、Be concise and on point、Communicating with executives、Listen、Be proactive、Be thorough 和 Take notes 7 个维度介绍作为 TL 时如何高效沟通。</p><p><a href="https://addyosmani.com/blog/communication-tech-lead/" target="_blank" rel="noopener noreferrer">https://addyosmani.com/blog/communication-tech-lead/</a></p><p>📒 React Re-Renders</p><p>通过这篇文章，我学到了「两个误解」、「一个比喻」和「一个技巧」。</p><p>两个误解是，1）state 变更会让整个 app re-render？不是，state 变更只会让当前组件及其子组件 re-render，2）组件 re-render 是因为 props 变更？也不是，props 往上可以追溯到 state 变更，是 state 变更导致了子组件 re-render，而不是由 props 变更引起。</p><p>上述误解 2 的一个例外是 React.memo，应用 React.memo 后的组件只有 props 变更才会触发 re-render。你可能会想：为什么这不是默认行为？因为作为开发者，我们往往高估了重新渲染的成本。对于 props 很多且没有很多子组件的组件来说，相比 re-render，检查 props 是否变更带来的消耗可能更大。因此，如果对每个组件都进行 React.memo，可能会产生反效果。</p><p>一个比喻是，每次渲染都是由照相机拍摄的快照，React 通过玩「找不同」的游戏找出两张照片之间的差异，然后决定是否 re-render。而 React.memo 则是懒惰的摄影师，如果你要求他为完全相同的东西拍 5 张照片，它会拍 1 张照片并给你 5 份。只有当你的指令改变时，他才会拍下一张新的照片。</p><p>一个技巧是，借助 React Devtools Chrome 插件，在「设置 &gt; Profiler」里开启「Record why each component rendered while profiling」，再通过录制的方式排查，就能知道每个 re-render 的原因。</p><p>原文链接：</p><p><a href="https://www.joshwcomeau.com/react/why-react-re-renders/" target="_blank" rel="noopener noreferrer">https://www.joshwcomeau.com/react/why-react-re-renders/</a></p><p>中文翻译：</p><p><a href="https://mp.weixin.qq.com/s/SH7N2f5ZhUhysQ7_G2s9rQ" target="_blank" rel="noopener noreferrer">【第2709期】一份详尽的 React re-render 指南</a></p><p>📒 深入解读新一代全栈框架 Fresh</p><p>从定位上来看，Fresh 属于 <strong>Web 全栈开发框架</strong>，相比 Next.js 和 Remix， Fresh 有哪些值得一提的亮点：</p><ul><li>Fresh 基于 Deno 运行时，由 Deno 原班人马开发，享有 Deno 一系列工具链和生态的优势，比如内置的测试工具、支持 http import 等等</li><li>渲染性能方面，Fresh 整体采用 Islands SSR 架构(之前介绍的 Astro 也是类似)，实现了客户端按需 Hydration，有一定的渲染性能优势</li><li>还有一个比较出色的点是构建层做到了 Bundle-less，即应用代码不需要打包即可直接部署上线</li><li>最后，不同于 Next.js 和 Remix，Fresh 的前端渲染层由 Preact 完成，包括 Islands 架构的实现也是基于 Preact，且不支持其它前端框架</li></ul><p>开发者并不需要手写路由文件，Fresh 可以自动地生成服务端的路由到文件的映射关系。很明显 Fresh 实现了 <strong>约定式路由</strong> 的功能，跟 Next.js 类似。</p><p><a href="https://mp.weixin.qq.com/s/8qNI4a-3P2KId9WRAnz2dw" target="_blank" rel="noopener noreferrer">深入解读新一代全栈框架 Fresh</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[8月21日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月21日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月21日内容汇总"/>
        <updated>2022-08-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 玩转 Chrome DevTools，定制自己的调试工具]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7133943494023839780" target="_blank" rel="noopener noreferrer">玩转 Chrome DevTools，定制自己的调试工具</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ukZxF_W6dahisVW_Xf6-TA" target="_blank" rel="noopener noreferrer">【第2707期】由 esbuild JavaScript API 看跨语言调用</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Mmj6jJkuQMIf5SGEi_pBaQ" target="_blank" rel="noopener noreferrer">Go 中闭包的底层原理是</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/o_cXCroRSK5HAKG0wjC29Q" target="_blank" rel="noopener noreferrer">使用 TypeScript 编写 React 的最佳实践！</a></p><p>📒 Webpack 构建优化</p><p><a href="https://tsejx.github.io/webpack-guidebook/best-practice/optimization/collection" target="_blank" rel="noopener noreferrer">https://tsejx.github.io/webpack-guidebook/best-practice/optimization/collection</a></p><p><a href="https://webpack.js.org/guides/code-splitting/" target="_blank" rel="noopener noreferrer">https://webpack.js.org/guides/code-splitting/</a></p><p>📒 k8s 部署相关</p><p>使用 Docker Desktop 搭建 k8s 集群</p><p><a href="https://mp.weixin.qq.com/s/DEZPCzQul7wnZKqm1Ue6rg" target="_blank" rel="noopener noreferrer">从Go程序第一行代码，到在 K8s 上运行，要经历多少步</a></p><p><a href="https://mp.weixin.qq.com/s/ZU61NIMxh_UOo-chNvkPXA" target="_blank" rel="noopener noreferrer">在K8S上的Web服务该怎么做域名解析呢</a></p><p><a href="https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/" target="_blank" rel="noopener noreferrer">https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/IYZrtK7pJTeCOBwY-sC9HA" target="_blank" rel="noopener noreferrer">字节一面：HTTPS 一定安全可靠吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cbKpWKWrhyJwKQhlyYhQ_w" target="_blank" rel="noopener noreferrer">如何在项目开发中逐步成长</a></p><p>📒 Golang 相关文章</p><p>Go 语言里使用 <code>io.Reader</code> 和 <code>io.Writer</code> 两个 interface 来抽象 <code>I/O</code>，他们的定义如下：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Reader </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">byte</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Writer </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">Write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">byte</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>io.Reader</code> 接口代表一个可以从中读取字节流的实体，而 <code>io.Writer</code> 则代表一个可以向其写入字节流的实体。</p><ul><li>⭐️ <a href="https://mp.weixin.qq.com/s/SpVTl64W1Exy8fuN15-kmA" target="_blank" rel="noopener noreferrer">Go指针的使用限制和突破之路</a></li><li>⭐️ <a href="https://mp.weixin.qq.com/s/TtN6NZ8hQ2AIf0C8wVzkjA" target="_blank" rel="noopener noreferrer">Go语言的IO库那么多，我该怎么选</a></li><li><a href="https://mp.weixin.qq.com/s/gYWhjh1BburgeAU72mn_aw" target="_blank" rel="noopener noreferrer">Go 眼中的文件系统是什么？ io.FS</a></li><li><a href="https://mp.weixin.qq.com/s/0c7emt54ayCrm1K16lk2SQ" target="_blank" rel="noopener noreferrer">如何更直观地理解 Go 调度过程</a></li><li><a href="https://mp.weixin.qq.com/s/FviFOLkIHuEjZdTg_qCoNQ" target="_blank" rel="noopener noreferrer">Go1.19 那些你不知道的新特性</a></li><li><a href="https://mp.weixin.qq.com/s/SrqJdng9cNUEVAS7nFaqAA" target="_blank" rel="noopener noreferrer">Go 中可别用复制锁，会有这些大问题！</a></li></ul><p>⭐️ <a href="https://mp.weixin.qq.com/s/fb2uUWz5ZjPEfYv_l6e4Zg" target="_blank" rel="noopener noreferrer">能ping通，TCP就一定能连通吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/RJp9s_shNckkHBqHsJThuA" target="_blank" rel="noopener noreferrer">Linux 是如何收发网络包的</a></p><p>📒 Golang 依赖注入相关文章</p><p><a href="https://dev.to/dryrainbow/dependency-injection-in-golang-35oa" target="_blank" rel="noopener noreferrer">https://dev.to/dryrainbow/dependency-injection-in-golang-35oa</a></p><p><a href="https://medium.com/avenue-tech/dependency-injection-in-go-35293ef7b6" target="_blank" rel="noopener noreferrer">https://medium.com/avenue-tech/dependency-injection-in-go-35293ef7b6</a></p><p><a href="https://medium.com/thirdfort/go-best-practices-how-to-code-comfortably-60118a27def8" target="_blank" rel="noopener noreferrer">https://medium.com/thirdfort/go-best-practices-how-to-code-comfortably-60118a27def8</a></p><p><a href="https://levelup.gitconnected.com/better-error-handling-in-golang-theory-and-practical-tips-758b90d3f6b4" target="_blank" rel="noopener noreferrer">https://levelup.gitconnected.com/better-error-handling-in-golang-theory-and-practical-tips-758b90d3f6b4</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cKC8u_43Ewqq0GAgErQO0w" target="_blank" rel="noopener noreferrer">【第2704期】网易严选多端组件库OSSA正式开源</a></p><p>📒 Golang 相关文章</p><p><a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUzNTY5MzU2MA==&amp;action=getalbum&amp;album_id=1323498303014780929&amp;scene=21&amp;from_msgid=2247484112&amp;from_itemidx=1&amp;count=3&amp;nolastread=1#wechat_redirect" target="_blank" rel="noopener noreferrer">Go 语言 Web 编程</a></p><p><a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUzNTY5MzU2MA==&amp;action=getalbum&amp;album_id=1325302744319737858&amp;scene=21&amp;from_msgid=2247484375&amp;from_itemidx=1&amp;count=3&amp;nolastread=1#wechat_redirect" target="_blank" rel="noopener noreferrer">Go 语言并发编程</a></p><p><a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUzNTY5MzU2MA==&amp;action=getalbum&amp;album_id=1809543596702777345&amp;scene=21&amp;from_msgid=2247492061&amp;from_itemidx=1&amp;count=3&amp;nolastread=1#wechat_redirect" target="_blank" rel="noopener noreferrer">Go 微服务实战</a></p><p>📒 React 18 新特性：Selective Hydration</p><p><a href="https://github.com/reactwg/react-18/discussions/37" target="_blank" rel="noopener noreferrer">https://github.com/reactwg/react-18/discussions/37</a></p><p>📒 <a href="https://juejin.cn/post/7122636487555809311" target="_blank" rel="noopener noreferrer">一个简洁、强大、可扩展的前端项目架构是什么样的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fxEKYW5cIKM5tec3VWwgSw" target="_blank" rel="noopener noreferrer">大家都能看得懂的源码之ahooks useInfiniteScroll</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/37DtrXeRioq-xSKayIJbCg" target="_blank" rel="noopener noreferrer">esModuleInterop 是如何影响 tsc 的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1h6yqCWyzYLM8WPGlGdtVA" target="_blank" rel="noopener noreferrer">【第2703期】软件架构手册</a></p><p>📒 <a href="https://juejin.cn/post/6844903956263501838" target="_blank" rel="noopener noreferrer">如何在 Web 上构建一个插件系统</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XX3Y1tKU-_oeNGsXfgcNQg" target="_blank" rel="noopener noreferrer">Go 的常量为什么只支持数字、字符串这样的基础类型</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DZbAq9fpPxElhfJCkY53GA" target="_blank" rel="noopener noreferrer">两万字详解！InnoDB锁专题！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cDCHV08x1rPiZVZMRFjWBg" target="_blank" rel="noopener noreferrer">细数线程池的10个坑</a></p><p>📒 <a href="https://juejin.cn/post/7132077894922141726" target="_blank" rel="noopener noreferrer">Chrome DevTools 远程调试安卓网页的原理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/RSSQymhS48pFXI2Z9JX6TA" target="_blank" rel="noopener noreferrer">Windows 滚动条如何美化成 macOS 那样</a></p><p>📒 <a href="https://juejin.cn/post/7131947887398748196" target="_blank" rel="noopener noreferrer">Go逃逸分析详解</a></p><p>📒 <a href="https://juejin.cn/post/7131717990558466062" target="_blank" rel="noopener noreferrer">GO面试必知必会面试题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1ZuhUA9Lt2uLFlamIY6fLQ" target="_blank" rel="noopener noreferrer">最简单的单例模式，Go版本的实现你写对了吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zyvO_hhUo1TRm6kMPcaFFQ" target="_blank" rel="noopener noreferrer">伙计，Go项目怎么使用枚举</a></p><p>📒 <a href="https://juejin.cn/post/7131928500373553160" target="_blank" rel="noopener noreferrer">Astro 1.0 正式发布，给前端带来了什么</a></p><p>📒 gum</p><p>迷人的 shell 脚本工具库，基于 go。</p><blockquote><p><a href="https://github.com/charmbracelet/gum" target="_blank" rel="noopener noreferrer">https://github.com/charmbracelet/gum</a></p></blockquote><p>📒 React Query 转 RTK</p><p>本文是作者和 React Query 斗争了一年之后，最终弃 React Query 投 RTK 的故事。</p><p>React Query 处理了复杂的缓存，并根据需要重新加载数据。用户使用 useQuery 调用 API 时，数据被存储在 React Query 的缓存中。缓存的数据可通过 getQueryData 读取。如果要更新数据，使用 useMutation 会更新服务群上的数据，同时在 onSuccess 或 onMutate 中更新 React Query 缓存中的数据。更新的最简单方法是调用 invalidateQueries。而缓存失效正是作者觉得 React Query 难以驾驭的主要原因。</p><p>然后作者在对比之后选择了 Redux + Redux Toolkit（RTK）。作者希望选择全局 store 的数据流，同时还对比了竞品比如 Valtio（见上图）。Redux 的优点是社区、文档、明确的数据结构，缺点是更多脚手架代码、需要用 reselect 或其他来做渲染优化、尺寸比较大（18K）。</p><p>编者注：如果我是作者，在需要全局 store 的前提下，会更倾向于选择 valtio 或 zustand。1）脚手架代码少，这一点对外来说很关键，2）性能更好（valtio 基于使用决定 re-render），3）redux 的单 store 在未来可能成为瓶颈，比如要做组件提取时，多 store 会更灵活一些。</p><blockquote><p><a href="https://www.basedash.com/blog/why-we-had-to-move-away-from-react-query" target="_blank" rel="noopener noreferrer">https://www.basedash.com/blog/why-we-had-to-move-away-from-react-query</a></p></blockquote><p>📒 Suspense</p><p>作者在一年前写了第一篇，这是第二篇。时隔一年，这篇是他几个月的研究成果。</p><p>这段时间发生了什么？1）React 团队创建 React 18 工作小组讨论区，提供更多深入的信息，同时用于收集反馈，2）React 18 稳定版发布，3）一篇 React Labs 的帖子，介绍 React 团队正在探索的内容。</p><p>React 18 有啥新特性？1）没有并发模式，取而代之的是并发功能，仅在子树中启用，原因是为了向后兼容，2）Transition 允许将不紧急的更新标记为过渡（未来可能成为默认行为），3）基于 Suspense 的 Streaming SSR 允许在所有 HTML 被渲染之前进行流化，并且在 HTML 被完全流化之前就可以开始水化（目前需搭配 React.lazy 使用），4）选择性水化，5）新 Hooks，比如 useId 可用来生成在客户端和服务端稳定的 ID，6）自动批处理 让多个 setState 只导致单一渲染。</p><p>React 下一步做什么？1）Cache 组件，允许请求库做与 Suspense + 并发渲染兼容的数据缓存，这是 Suspense 目前缺的一环，2）React Server Component，3）用于 Assets 资源加载的 Suspense，比如字体、CSS 和字体等会在加载时导致布局偏移和混乱，4）React 编译器优化，React 慢的原因之一是因为有大量不必要的 re-render，自动插入 memo hook 可以提升性能，这在 React Conf 2021 中有过介绍，5）SuspenseList，在处理 Suspense 列表时有用，比如文章、评论或消息，允许协调子节点，决定他们显示的顺序，6）Offscreen API，允许保留 unmount 组件的状态，或者预先渲染用户可能会执行的 transition，比如做基于路由的预渲染。</p><p>跳出 React 从整体社区角度看。1）流式服务端渲染是为了提高响应速度，所以尽可能早地 flush，MarkoJS 在 2014 年开始支持，更早一些 Facebook 在 2009 年也有一门叫 BigPipe 的技术，2）SSR 在网络方面会更快，但同步水化依旧会成为大型项目的性能瓶颈，Islands architecture(群岛架构） 可以解这个问题，3）细粒度响应式，「React 虽然叫 react，但实际上不是 react」，响应式是框架中很流行的一种优化方法，比如 SolidJS，React 团队也有考虑过这个问题，但选择不追求，Dan 早在 2019 年就写过这个话题，4）Transition API 不算新技术，谷歌地图也有类似实现，同时 Scheduling（调度）问题正在通过标准的方式解决，5）SRC（服务端渲染组件）也不是新想法，2018 年就有 Phoenix LiveView 的实现，通过服务端状态和渲染实现 0 JS 的交互功能。</p><p>最后，作者还发现，React 项目内部子项目代号均是以 F 开头。比如 Fiber 是实现了异步渲染的重写的核心代号；Fizz 是新的服务器端渲染架构的代号、Flight 是服务器组件的代号、Fire、Flare 等。</p><blockquote><p><a href="https://blog.6nok.org/the-suspense-is-killing-me:-part-2/" target="_blank" rel="noopener noreferrer">https://blog.6nok.org/the-suspense-is-killing-me:-part-2/</a></p></blockquote><p>📒 React TypeScript 备忘录</p><p>一份很全面的 React TypeScript 备忘录。</p><blockquote><p><a href="https://react-typescript-cheatsheet.netlify.app/" target="_blank" rel="noopener noreferrer">https://react-typescript-cheatsheet.netlify.app/</a></p></blockquote><p>📒 React re-render 指南</p><p>关于 React 重渲染的系列指南，图文并茂，同时提供了代码示例和扩展资料。</p><blockquote><p><a href="https://www.developerway.com/posts/react-re-renders-guide" target="_blank" rel="noopener noreferrer">https://www.developerway.com/posts/react-re-renders-guide</a></p></blockquote><p>📒 ESLint 推出新的配置系统</p><p>回顾当前的 eslintrc 配置系统演进史，每一步的演化在当时来看都是不错的选择，比如 extends、Personal configs、多种配置文件格式、可共享的配置和依赖项(npm 背锅)、root、overrides、添加 extends 到 overrides 等等。</p><p>然而时至今日，随着 JavaScript 项目越来越庞大，从整体上再来看这些配置就太复杂了。为了简化配置，ESLint 团队经过 18 个月的修订和讨论，决定着手构建一个全新的配置系统 flat config，现在可以在 ESLint v8.21.0 中通过 API 使用。</p><blockquote><p><a href="https://eslint.org/blog/2022/08/new-config-system-part-1/" target="_blank" rel="noopener noreferrer">https://eslint.org/blog/2022/08/new-config-system-part-1/</a></p></blockquote><blockquote><p><a href="https://eslint.org/blog/2022/08/new-config-system-part-2/" target="_blank" rel="noopener noreferrer">https://eslint.org/blog/2022/08/new-config-system-part-2/</a></p></blockquote><blockquote><p><a href="https://eslint.org/blog/2022/08/new-config-system-part-3/" target="_blank" rel="noopener noreferrer">https://eslint.org/blog/2022/08/new-config-system-part-3/</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/3fMZN_LidCi5fiD16nNWWA" target="_blank" rel="noopener noreferrer">字节一面：TCP 和 UDP 可以使用同一个端口吗</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[8月14日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月14日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月14日内容汇总"/>
        <updated>2022-08-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 将微前端做到极致-无界方案]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/hRR_sp3w_dgnUbdNXMuL7w" target="_blank" rel="noopener noreferrer">将微前端做到极致-无界方案</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/9eZxW9qihgQlbBP0D0ZMQQ" target="_blank" rel="noopener noreferrer">【第2701期】技术Leader如何创造业务价值</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/456483953" target="_blank" rel="noopener noreferrer">Monorepo 下的模块包设计实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/rZ96wy8xUrx4T1qG5OKS0w" target="_blank" rel="noopener noreferrer">【TypeScript】never 和 unknown 的优雅之道</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/nk5SN8AKwyFkUTEOiLCBdQ" target="_blank" rel="noopener noreferrer">Bundle-less 的思考和实践分享</a></p><p>📒 <a href="https://segmentfault.com/a/1190000042271919" target="_blank" rel="noopener noreferrer">React Fiber架构原理剖析</a></p><p>📒 <a href="https://juejin.cn/post/7129747165794009101" target="_blank" rel="noopener noreferrer">【万字】优化Webpack？肘，跟我进屋聊聊</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-eEMSn2WpDiMbNSBgY3-pg" target="_blank" rel="noopener noreferrer">字节的前端监控 SDK 是怎样设计的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ioDYZjdSii3WUvL9xqc_Sg" target="_blank" rel="noopener noreferrer">别再乱打日志了，这份 Java 日志规范，应有尽有，建议收藏！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/l3jJHIcqMzCcezbpboqyvQ" target="_blank" rel="noopener noreferrer">explain | 索引优化的这把绝世好剑，你真的会用吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3jrf1GKBBbVzcvJxqYnx9Q" target="_blank" rel="noopener noreferrer">这11条接口性能优化技巧，利好每日睡眠</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Y1Mh-99cgQWuCQ53wAxkUQ" target="_blank" rel="noopener noreferrer">顺丰快递：请签收MySQL灵魂十连</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/UL5d3P6sjT36njR4RYMFkQ" target="_blank" rel="noopener noreferrer">Go Mod小知识：伪版本</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XPPwHd7eDUjvzsnuFwgbyw" target="_blank" rel="noopener noreferrer">Go ORM 单元测试全流程讲解</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/r30z2i_sSuRfEnM_23wFlg" target="_blank" rel="noopener noreferrer">超全总结：Go语言如何操作文件</a></p><p>📒 React 服务端渲染遇到的问题</p><p>在服务端渲染场景下，不能使用 <code>style-loader</code>，需要用 <code>isomorphic-style-loader</code> 注入样式。</p><blockquote><p><code>style-loader</code> 内部使用了 dom API 把样式注入到 <code>style</code> 标签中，在 Node 环境下会报错</p></blockquote><p>React 期望在服务端和客户端渲染的内容是相同的，客户端渲染会默认复用服务端渲染的 dom。如果需要在服务端和客户端上渲染不同的内容，可以设置一个 <code>isClient</code> 变量：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyComponent</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">PureComponent</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">isClient</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">componentDidMount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 这里在客户端 hydrate 的时候执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">setState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">isClient</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> isClient </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">isClient</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 当需要渲染的组件需要访问浏览器 API，在 Node 环境会报错</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 这里可以渲染 fallback 的内容</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 在客户端可以正常渲染组件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>当需要渲染的组件需要访问浏览器 API（例如 <code>window</code>、<code>document</code>、<code>location</code>），在 Node 环境会报错。在服务端渲染的时候，可以先渲染 fallback 内容，在客户端 hydrate 的时候，再渲染正常组件。</p><p>另外有一些 SDK，内部可能也访问了浏览器 API，这种情况下不能直接在构造器中初始化实例，可以在 <code>componentDidMount</code> 钩子中延迟初始化。</p></div></div><blockquote><p><a href="https://17.reactjs.org/docs/react-dom.html#hydrate" target="_blank" rel="noopener noreferrer">https://17.reactjs.org/docs/react-dom.html#hydrate</a></p></blockquote><p>📒 vite 代码压缩遇到的问题</p><p>vite 默认使用 esbuild 压缩，esbuild 不仅会做常规的压缩，而且还会在 <code>target</code> 配置允许的范围内做一些语法转换，进一步减小 bundle 体积。</p><p>例如在业务中有下面一段代码：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword control-flow" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 这边没有用到 err 参数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>经过 esbuild 压缩之后，<code>try...catch</code> 后面的括号直接不见了（这实际上是 ES2019 中的 <code>optional-catch-binding</code> 语法），在一个老业务工程构建的时候，Babel 无法识别这种语法，直接报错了：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword control-flow" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>有两种解决方案：</p><ul><li>一种是使用 terser 压缩，设置 <code>minify: "terser"</code></li><li>另一种继续使用 esbuild，但是手动设置 <code>target: "es2015"</code></li></ul><blockquote><p><a href="https://vitejs.dev/config/build-options.html#build-target" target="_blank" rel="noopener noreferrer">https://vitejs.dev/config/build-options.html#build-target</a></p></blockquote><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>在一般前端项目中，<code>target</code> 配置是针对 Babel 的，即最终的产物兼容性由 Babel 决定。</p><p>但是在 Vite 中，Babel 只参与部分 esbuild 尚不支持的提案阶段的语法转换，并不决定最终产物兼容性，最终的兼容性由 esbuild 决定。注意 esbuild 默认的 target 值为 <code>"esnest"</code>，即 esbuild 认为环境支持最新的 JS 语法特性。但是在 Vite 中，<code>build.target</code> 默认为一个特殊值 <code>"modules"</code>（即支持原生 ES Module、动态导入语法和 <code>import.meta</code> 语法，对应 Chrome &gt;=87），最低可以支持 <code>"es2015"</code>。</p><p>注意 Vite 默认只做语法转换，并不会引入 polyfill（适合第三方库开发，由业务工程 <code>@babel/preset-env</code> 配置 <code>useBuiltIns: "entry"</code> 统一引入 polyfill）。如果产物需要直接在浏览器中运行，则需要 <code>@vitejs/plugin-legacy</code> 插件。该插件会对最终 bundle 中每个 chunk，使用 <code>@babel/preset-env</code> 转换生成对应的 legacy chunk，同时根据 <code>target</code> 配置的目标浏览器兼容性和实际用到的 API，生成一个 polyfill chunk。</p><p><a href="https://vitejs.dev/guide/build.html#browser-compatibility" target="_blank" rel="noopener noreferrer">https://vitejs.dev/guide/build.html#browser-compatibility</a></p></div></div><p>📒 Golang 标准库 strings</p><p>重点看一下 <code>strings.Builder</code> 的用法。</p><p><a href="https://blog.csdn.net/qq_24433609/article/details/124500115" target="_blank" rel="noopener noreferrer">Go 学习之 strings.Builder 篇</a></p><p><a href="https://www.cnblogs.com/cheyunhua/p/15769717.html" target="_blank" rel="noopener noreferrer">Go 字符串拼接6种，最快的方式 -- strings.builder</a></p><p><a href="https://blog.csdn.net/qq_41035588/article/details/108289761" target="_blank" rel="noopener noreferrer">Go拼接字串的三种方法 Go1.10中的strings.Builder</a></p><p><a href="https://pkg.go.dev/strings@go1.19" target="_blank" rel="noopener noreferrer">https://pkg.go.dev/strings@go1.19</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/usDh1-Wzxrf4BftfWhwduA" target="_blank" rel="noopener noreferrer">你需要知道的TypeScript高级类型</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/HaF9qieEJWNUoyY9qTvnKw" target="_blank" rel="noopener noreferrer">Go 的时间转换和时区校对总记不住？给你一份备忘单</a></p><p>📒 <a href="https://juejin.cn/post/7121520457760653349" target="_blank" rel="noopener noreferrer">两个真实线上升级故障让你彻底搞懂package.json中的脱字符(^)</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6Er2IQEXXNc8Sb5vVJZZOQ" target="_blank" rel="noopener noreferrer">【第2696期】React 状态管理的新浪潮</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/X60eIQcEAJz8tvNz5qArxg" target="_blank" rel="noopener noreferrer">Go 创始人教你如何处理错误</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/4Sxal7N-uZ8gvphC8XWo8A" target="_blank" rel="noopener noreferrer">总监又来了，人狠话不多，这篇 gRPC，小弟佩服！</a></p><p>📒 React 性能优化, 从 500 毫秒到 1.7 毫秒</p><blockquote><p><a href="https://orizens.com/blog/500ms-to-1-7ms-in-react-a-journey-and-a%20checklist/" target="_blank" rel="noopener noreferrer">https://orizens.com/blog/500ms-to-1-7ms-in-react-a-journey-and-a%20checklist/</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7129520818232492040" target="_blank" rel="noopener noreferrer">UMD 的包如何导出 TS 类型</a></p><p>📒 <a href="https://juejin.cn/post/7116141318853623839" target="_blank" rel="noopener noreferrer">为什么 React 的 Diff 算法不采用 Vue 的双端对比算法</a></p><p>📒 <a href="https://juejin.cn/post/7129267782515949575" target="_blank" rel="noopener noreferrer">🚀Turborepo：发布当月就激增 3.8k Star，这款超神的新兴 Monorepo 方案，你不打算尝试下吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ptJK7CDHCr6P4JCdsUXKdg" target="_blank" rel="noopener noreferrer">搞清楚 Go Mod的版本和伪版本，下次别乱用了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Nu4XCuF4d_BaAkmwRr3f4A" target="_blank" rel="noopener noreferrer">掌握 TypeScript 中的映射类型</a></p><p>📒 React Re-render 指南</p><p>什么是 re-render？什么是必要的 re-render 和不必要的 re-render？如果你对这些问题还模模糊糊的，在这篇文章中可以找到答案。</p><p>有四个原因可以让一个组件重新渲染自己：状态变化、父级（或子级）重新渲染、上下文变化和 hooks 变化。</p><p>通过 composition（组合）可以避免 re-render。有几种方式，1）把状态下移，避免上层组件 re-render，让 re-render 保持在一个很小的范围之内，2）children as props，作为 props，子组件不会受 state 变更的影响，3）component as props，避免 component re-render。</p><p>通过 React.memo 可以避免 re-render，被 memo 的组件只在 props 变更时会 re-render。有几种方式，1）对于带 props 的 component，需对非原始值的 props 做 memo，2）components as props or children，对子组件做 memo 而不要对父组件做 memo。</p><p>什么时候应该用 useMemo/useCallback？1）React.memo 过的组件的 props 应该用，因为他们只有 props 变更时才会 re-render，所以反之非 React.memo 过的组件的 props 无需使用，因为都会 re-render，用了也白用，2）useEffect、useMemo、useCallback 中非原始值的依赖应该用，3）重消耗（比如生成渲染树）的部分应该用，反之轻消耗不要用，因为 useMemo/useCallback 本身也有消耗。</p><p>如何防止 Context 引起的 re-render？1）memo context value，避免父级组件 re-render 导致 value 变更从而让依赖 context 的地方全部 re-render，2）拆分 data 和 API（getter 和 setter），这样 getter 变更时依赖 setter 的部分不会 re-render，3）把数据拆小，4）使用 context selector 比如 use-context-selector。</p><blockquote><p><a href="https://www.developerway.com/posts/react-re-renders-guide" target="_blank" rel="noopener noreferrer">https://www.developerway.com/posts/react-re-renders-guide</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/vRI-bFB4_IEaoCCQcMqZjw" target="_blank" rel="noopener noreferrer">明明加了唯一索引，为什么还是产生重复数据</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/0Jn1CHAVyX1U8RD2OUJENQ" target="_blank" rel="noopener noreferrer">现代前端测试框架 Vitest 的一些落地实践感悟</a></p><p>📒 <a href="https://juejin.cn/post/7129130418657296421" target="_blank" rel="noopener noreferrer">如何用 Project Reference 优化 tsc 编译性能</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[8月7日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月7日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/8月7日内容汇总"/>
        <updated>2022-08-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 互联网公司都怎么实现分页的，拿 MySQL 使劲Limit]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/O6sgYSpXBPwAA4Qcstj-BA" target="_blank" rel="noopener noreferrer">互联网公司都怎么实现分页的，拿 MySQL 使劲Limit</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/OKUeAdicn0Bvkz8dYx1epQ" target="_blank" rel="noopener noreferrer">拒绝 Go 代码臃肿，其实在这几块可以用下观察者模式</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Yh2dOC8Pumeis-h1_gMLjg" target="_blank" rel="noopener noreferrer">记一次线上超时问题的发现、排查、定位以及解决过程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Dn2oM89mHEgoz8yVQnNEoQ" target="_blank" rel="noopener noreferrer">这不会又是一个Go的BUG吧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/YojNHW7kkjmmdjqBXCuQYA" target="_blank" rel="noopener noreferrer">这三个 Go 水平自测题，手写不出来还是先老实上班吧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pR_XHTnhft2Hi_mY7JuEJg" target="_blank" rel="noopener noreferrer">不想Go 错误处理太臃肿，可以参考这个代码设计</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/HuZn9hnHUBx3J4bAGYBYpw" target="_blank" rel="noopener noreferrer">关于Go程序错误处理的一些建议</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/tw4lD0XA67yJKAwIWVicIQ" target="_blank" rel="noopener noreferrer">你见过哪些目瞪口呆的 Java 代码优化技巧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/AOshaWGmLw6uw92xKhLAvQ" target="_blank" rel="noopener noreferrer">聊聊 13 种锁的实现方式</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cPrhhSv1KkwkYdxPAfvkDA" target="_blank" rel="noopener noreferrer">代码越写越乱？那是因为你没用责任链！</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/QWoVKFzFJUHNmmz89mMH1g" target="_blank" rel="noopener noreferrer">社招后端21连问（三年工作经验一面）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/qrmdU5ijy3P6SeP-MAVjJw" target="_blank" rel="noopener noreferrer">Spring Boot 实现接口幂等性的 4 种方案</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ANuNr1mtFZCu4S4WuNYNlg" target="_blank" rel="noopener noreferrer">前端运维部署那些事</a></p><p>📒 rollup 最佳实践！可调试、编译的小型开源项目思路</p><p>tsc 可以只生成类型声明文件：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tsc  --emitDeclarationOnly --declaration --project ts.config.json --outDir dist/esm</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://mp.weixin.qq.com/s/-fn8ynYuvRcnDLB5VqRBFg" target="_blank" rel="noopener noreferrer">rollup 最佳实践！可调试、编译的小型开源项目思路</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Gd7RLj1aRoJa6Jd2gi8vNA" target="_blank" rel="noopener noreferrer">脚本任务执行器 —— npm-run-all 源码解析</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/79ELfeZ09HAl1lFaeONyLA" target="_blank" rel="noopener noreferrer">2022年值得推荐的React库！</a></p><p>📒 <a href="https://juejin.cn/post/7121244973558661150" target="_blank" rel="noopener noreferrer">超大体量项目，微前端落地方案，看完后悔来找我</a></p><p>📒 <a href="https://juejin.cn/post/7127953386514677790" target="_blank" rel="noopener noreferrer">如何解决前端常见的竞态问题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2IGogbnvxG1O_PYy49fv8g" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#88-1 Not using testing utility packages</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DnCc5NIrMzvJuTF_xN6RYQ" target="_blank" rel="noopener noreferrer">字节二面，差点没答好</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pxbQbvZP2IWMQzA7v8YV4w" target="_blank" rel="noopener noreferrer">如何提高 TypeScript 的代码质量</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/A6lTimcViHjIigj4V6Dasg" target="_blank" rel="noopener noreferrer">谁说 Mysql 单表最大 2000 W ？我硬要塞它 1 个亿！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/teFxhgzag8k5EXVnccdMkA" target="_blank" rel="noopener noreferrer">初探 Vue3 编译之美</a></p><p>📒 Go 1.19 is released</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ go </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> golang.org/dl/go1.19@latest</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>go 命令使用：<a href="https://pkg.go.dev/cmd/go" target="_blank" rel="noopener noreferrer">https://pkg.go.dev/cmd/go</a></p></blockquote><p>📒 GitHub Trending - TypeScript</p><p><a href="https://github.com/trending/typescript" target="_blank" rel="noopener noreferrer">https://github.com/trending/typescript</a></p><p>📒 <a href="https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&amp;mid=2247492602&amp;idx=1&amp;sn=135fd5b530189f13e0395414a6b47893" target="_blank" rel="noopener noreferrer">【表达式计算】双栈 : 表达式计算问题的通用解法</a></p><p>📒 构建自己的 Web 框架</p><p>这篇文章解释了如何构建基于 React 的简易 Web 框架，并使用 Vercel 的 Build Output API 进行部署。</p><p>Build Output API 是一个基于文件系统的规范，用于生成 Vercel 部署的目录结构。框架作者可以将此目录结构实现为他们构建命令的输出，以便框架可以利用所有 Vercel 的平台功能(Serverless Functions，Edge Functions，路由，缓存等)，Astro已经成功与 Vercel 集成。</p><p><a href="https://vercel.com/blog/build-your-own-web-framework" target="_blank" rel="noopener noreferrer">https://vercel.com/blog/build-your-own-web-framework</a></p><p>📒 <a href="https://github.com/BetaSu/big-react" target="_blank" rel="noopener noreferrer">从零实现 React v18 的核心功能</a></p><p>📒 <a href="https://deno.com/blog/roll-your-own-javascript-runtime" target="_blank" rel="noopener noreferrer">Roll your own JavaScript runtime</a></p><p>📒 <a href="https://github.com/ronami/HypeScript" target="_blank" rel="noopener noreferrer">用 TS 的类型系统实现一个 TS 类型系统</a></p><p>📒 <a href="https://github.com/sunym1993/flash-linux0.11-talk" target="_blank" rel="noopener noreferrer">像小说一样品读 Linux 0.11 核心代码</a></p><p>📒 <a href="https://juejin.cn/post/7126921039098937357" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 46 期：Chrome 三方 cookie 计划、npm 引入更多安全增强功能、Awesome Bun</a></p><p>⭐️ 看一下 React 15.x 源码</p><blockquote><p><a href="https://github.com/Lucifier129/react-lite" target="_blank" rel="noopener noreferrer">https://github.com/Lucifier129/react-lite</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/UELHBolk-UVC45H1QvtrLQ" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#87 Not dealing with the time API efficiently</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/8cXYXAHZCJMPSaaMpDqYtQ" target="_blank" rel="noopener noreferrer">用了TCP协议，就一定不会丢包吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hVoVdvt_sHUuVxvfSwgEVQ" target="_blank" rel="noopener noreferrer">【第2688期】关于低代码平台建设的思考与实践暨BPM表单设计器前端技术解析</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[7月31日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月31日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月31日内容汇总"/>
        <updated>2022-07-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 全网最优雅的 React 源码调试方式]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7126501202866470949" target="_blank" rel="noopener noreferrer">全网最优雅的 React 源码调试方式</a></p><p>📒 <a href="https://juejin.cn/post/7126477752718327839" target="_blank" rel="noopener noreferrer">如何实现一个跨框架的组件库文档</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1BdXL5dQfP6DnK7iJs6zGQ" target="_blank" rel="noopener noreferrer">入职Apifox研发组半年，我所提升的软技能｜文末抽书</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/cdc1NCSkvAU4Urk2wVFDMw" target="_blank" rel="noopener noreferrer">几个提升Go语言开发效率的小技巧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/15YxshMsZ7FJyLUfXZHqCQ" target="_blank" rel="noopener noreferrer">最近对前端构建工具的一些理解</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yUg-9H0GgzbavuxuU8Aahw" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#86 Sleeping in unit tests</a></p><p>📒 <a href="https://juejin.cn/post/7125613440000851975" target="_blank" rel="noopener noreferrer">超实用的Chrome DevTools调试技巧</a></p><p>📒 开源项目推荐</p><p>用 Go 写的 GUI gRPC 客户端。作者在调试 gPRC 接口时，发现没有类似 postman 趁手的 gPRC 客户端，所以就自己动手写了一个然后开源了。</p><blockquote><p><a href="https://github.com/crossoverJie/ptg" target="_blank" rel="noopener noreferrer">https://github.com/crossoverJie/ptg</a></p></blockquote><p>Go DDD 示例项目。该项目通过一个预约系统的示例，展示了如何在 Go 项目中实现领域驱动设计(DDD)和读写分离架构(CQRS)。</p><blockquote><p><a href="https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example" target="_blank" rel="noopener noreferrer">https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example</a></p></blockquote><p>一款静态应用程序安全测试(SAST)工具。它可以检测项目中是否包含密码、API Key、token 等信息，还能够轻松整合到 Git Hook 和 GitHub Action，实现提交代码时自动检测，通过告警和阻止 push 等方式，有效地防止敏感信息泄漏。</p><blockquote><p><a href="https://github.com/zricethezav/gitleaks" target="_blank" rel="noopener noreferrer">https://github.com/zricethezav/gitleaks</a></p></blockquote><p>在线可视化正则编辑器。该项目可将输入的正则表达式，自动生成对应的可视化图形，支持通过编辑图形节点修改正则表达式，以及对正则表达式进行测试等功能。</p><blockquote><p><a href="https://github.com/Bowen7/regex-vis" target="_blank" rel="noopener noreferrer">https://github.com/Bowen7/regex-vis</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/ORqdfZZ8qFyJdYTRwEULgQ" target="_blank" rel="noopener noreferrer">前端构建效率优化之路</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DuQzAumv_eB6Wc-YGVbe5g" target="_blank" rel="noopener noreferrer">Esbuild Bundler HMR</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bHdzGYSKC9SNoA7dpVvNsw" target="_blank" rel="noopener noreferrer">面试突击69：TCP 可靠吗？为什么</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/NUnaiVWADxzDOYPQdAwm6w" target="_blank" rel="noopener noreferrer">招银网络一面：AOP 了解吗？有什么用？切面执行顺序如何控制</a></p><p>⭐️ <a href="https://juejin.cn/post/7125066863150628900" target="_blank" rel="noopener noreferrer">Nest 的实现原理？理解了 reflect metadata 就懂了</a></p><p>📒 <a href="https://juejin.cn/post/7123969545387114509" target="_blank" rel="noopener noreferrer">耽误你十分钟！🎃你可能用得上这些webpack5新特性</a></p><p>📒 <a href="https://juejin.cn/post/7118782372220567566" target="_blank" rel="noopener noreferrer">入职即巅峰？🧨基建优化项目体积减少20%！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XznUiQUq5vRWFLgbz2u8Dg" target="_blank" rel="noopener noreferrer">简单好用的前端拖拽排序库</a></p><p>📒 <a href="https://juejin.cn/post/7124601707702517797" target="_blank" rel="noopener noreferrer">你能给前端工程化下个定义么</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KsoSwA73PzGwYMqZOwUvNQ" target="_blank" rel="noopener noreferrer">你需要知道的ES6—ES13开发技巧！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/PL_uWkSTo12hxmxMmUKndw" target="_blank" rel="noopener noreferrer">【第2682期】前端场景下请求的Race Conditions</a></p><p>📒 介绍几个相对冷门的 React Hook</p><blockquote><p><a href="https://css-tricks.com/react-hooks-the-deep-cuts/" target="_blank" rel="noopener noreferrer">https://css-tricks.com/react-hooks-the-deep-cuts/</a></p></blockquote><p>📒 Remix 和 Next.js 的区别</p><p>本文对这两个基于 React 的框架进行了逐个特性的比较，它们有很多相似之处，但也有一些关键的区别。</p><blockquote><p><a href="https://www.smashingmagazine.com/2022/07/look-remix-differences-next/" target="_blank" rel="noopener noreferrer">https://www.smashingmagazine.com/2022/07/look-remix-differences-next/</a></p></blockquote><p>📒 阅读源码之 React 篇</p><p>本文并不是要详尽地描述 React 是如何工作的，而是主要关注了 React 的设计和 React 开发人员多年来采用的实践。</p><blockquote><p><a href="https://alexkondov.com/readint-source-code-react/" target="_blank" rel="noopener noreferrer">https://alexkondov.com/readint-source-code-react/</a></p></blockquote><p>📒 <a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-generics/" target="_blank" rel="noopener noreferrer">编程语言是如何实现泛型的</a></p><p>📒 Vue 编译三部曲</p><p><a href="https://mp.weixin.qq.com/s/5GSrv0xV5a1VqkKuPGgTRw" target="_blank" rel="noopener noreferrer">Vue 编译三部曲：如何将 template 编译成 AST</a></p><p><a href="https://mp.weixin.qq.com/s/-Wo1_GfMyVgDckpNnL42wQ" target="_blank" rel="noopener noreferrer">Vue 编译三部曲：模型树优化</a></p><p><a href="https://mp.weixin.qq.com/s/K0za54kUIYXXpz3BS8XQkw" target="_blank" rel="noopener noreferrer">Vue 编译三部曲：最后一曲，render code 生成</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3fMZN_LidCi5fiD16nNWWA" target="_blank" rel="noopener noreferrer">字节一面：TCP 和 UDP 可以使用同一个端口吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-z809aeSyvZsdKcWKSUrgA" target="_blank" rel="noopener noreferrer">如何在繁重的工作中管理好自己的时间和精力</a></p><p>📒 <a href="https://juejin.cn/post/7121378029682556958" target="_blank" rel="noopener noreferrer">「万字总结」🍒动画 + 大白话讲清楚React渲染原理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-UOG3Pn9aNxRMBtncGjF-w" target="_blank" rel="noopener noreferrer">Go语言中常见100问题-#85 Not using table-driven tests</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JmHNfU11kbHGOnHi4kCcmQ" target="_blank" rel="noopener noreferrer">小程序不让用 JS 解释器？那我再肛一次鹅厂</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[7月24日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月24日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月24日内容汇总"/>
        <updated>2022-07-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 NestJS v9 发布]]></summary>
        <content type="html"><![CDATA[<p>📒 NestJS v9 发布</p><blockquote><p><a href="https://trilon.io/blog/nestjs-9-is-now-available" target="_blank" rel="noopener noreferrer">https://trilon.io/blog/nestjs-9-is-now-available</a></p></blockquote><p>📒 如何遍历 <code>map</code></p><p>首先，<code>map</code> 本身是可迭代对象，可以通过 <code>for...of</code> 遍历。</p><p>第二，可以将 <code>map</code> 转为数组进行遍历，实际还是利用了迭代器接口，但是可以利用数组方法链式调用。</p><blockquote><p><code>map</code> 默认迭代器接口是 <code>entries</code>，可以自定义例如 <code>[...map.values()]</code></p></blockquote><p>📒 开发小技巧</p><p>Antd 的 Modal 既可以通过组件方式，也可以通过 modal method 方式使用，后者比组件更方便，不需要自己维护状态，但是会有一个问题，如果需要通过弹框内部的按钮，控制弹框更新、关闭，我们没办法直接给弹框内部的元素传递 <code>modal.update</code>，因为此时 <code>Modal.success()</code> 还没有执行结束，<code>modal</code> 是 <code>undefined</code>，如何解决呢？</p><p>实际上可以通过不可变引用解决这个问题，我们先定义一个对象 <code>ctx</code>，在里面定义一个 <code>update</code> 方法，但什么也不做。然后给弹框内部按钮传入 <code>(e) =&gt; ctx.update(e)</code>，这样是可以正常调用，不会报错。然后在 <code>Modal.success()</code> 执行完成之后，这个时候就可以访问 <code>modal</code> 对象了，我们用 <code>modal.update</code> 去替换之前的空函数，这样当事件触发之后，调用的 <code>modal.update()</code> 就可以控制弹框更新了。</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">renderQuizModal</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  quizId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  unitId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  handleOk</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> ctx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">update</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CheckboxChangeEvent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> modal </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Modal</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">success</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    title</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> quizName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    width</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">600</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    okButtonProps</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      disabled</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    content</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Checkbox onChange</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CheckboxChangeEvent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> ctx</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">update</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        勾选此项</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">Checkbox</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">onOk</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      handleOk</span><span class="token operator" style="color:#393A34">?.</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ctx</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function-variable function" style="color:#d73a49">update</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CheckboxChangeEvent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    modal</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">update</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      okButtonProps</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        disabled</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">target</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">checked</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如何强制重新挂载组件？如果修改 <code>props</code> 或者 <code>setState</code> 只是触发组件 rerender，实际上是组件更新的过程，有时候需要强制组件重新挂载，可以修改组件的 <code>key</code>。</p><p>为何有时候没有给域名配置 host 还是可以访问？这是因为在容器中部署，可以通过 Docker 的 Networking 实现容器通信。</p><p>⭐️ <a href="https://juejin.cn/post/7122617883837857806" target="_blank" rel="noopener noreferrer">「React进阶」React中没有keepalive？没事！手把手教你从零到一设计并实现一个！</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/MNw8SBvQLJ7WtNPROEL9og" target="_blank" rel="noopener noreferrer">现在前端面试都问什么「字节、蚂蚁、美团、滴滴面试小记」</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/aXsmf95WsB31r5PnOZEF9A" target="_blank" rel="noopener noreferrer">2022 年值得推荐的 Vue 库</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/jqRxNAI5C2NdxVX-pthFpg" target="_blank" rel="noopener noreferrer">【第2676期】一个 Safari 的小 Bug，探索出了 fetch 和 xhr的新玩法</a></p><p>📒 <a href="https://juejin.cn/post/7122114817581645832" target="_blank" rel="noopener noreferrer">Vite 也可以模块联邦</a></p><p>📒 <a href="https://juejin.cn/post/7121929203032784910" target="_blank" rel="noopener noreferrer">开发一个 CLI 模板库可以点亮哪些技能点</a></p><p>📒 Golang 实现一个 JS 打包器</p><p>Golang 解析 JS AST：</p><ul><li><a href="https://github.com/robertkrimen/otto" target="_blank" rel="noopener noreferrer">https://github.com/robertkrimen/otto</a></li><li><a href="https://pkg.go.dev/github.com/robertkrimen/otto/parser" target="_blank" rel="noopener noreferrer">https://pkg.go.dev/github.com/robertkrimen/otto/parser</a></li></ul><p>Webpack 打包原理：</p><ul><li><a href="https://juejin.cn/post/6854573217336541192" target="_blank" rel="noopener noreferrer">手写webpack核心原理，再也不怕面试官问我webpack原理</a></li><li><a href="https://juejin.cn/post/6961961165656326152" target="_blank" rel="noopener noreferrer">做了一夜动画，让大家十分钟搞懂Webpack</a></li></ul><p>📒 <a href="https://juejin.cn/post/6893338774088974343" target="_blank" rel="noopener noreferrer">天天造轮子第七天 - 中间件实现 - Compose 的 N 种姿势</a></p><p>📒 <a href="https://juejin.cn/post/7117886038126624805" target="_blank" rel="noopener noreferrer">使用Vite和TypeScript带你从零打造一个属于自己的Vue3组件库</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/rFb07qMzV-JrzvVlDEgUAg" target="_blank" rel="noopener noreferrer">如何使用 React Hooks 重构类组件</a></p><p>📒 Why DRY is the most over-rated programming principle</p><blockquote><p><a href="https://gordonc.bearblog.dev/dry-most-over-rated-programming-principle/" target="_blank" rel="noopener noreferrer">https://gordonc.bearblog.dev/dry-most-over-rated-programming-principle/</a></p></blockquote><p>📒 What makes a great software engineer</p><blockquote><p><a href="https://swizec.com/blog/what-makes-a-great-software-engineer/" target="_blank" rel="noopener noreferrer">https://swizec.com/blog/what-makes-a-great-software-engineer/</a></p></blockquote><p>📒 构建面向未来的前端架构</p><p>本文是关于前端架构的组件部分。如果有写过组件，可能都有遇到随着业务迭代而快速增加复杂度，最终写出臃肿不堪难以维护的组件。为啥别人写的代码简洁易懂？缺的是经验吗？不是，缺的是方法论。我觉得此方法同样适用非组件场景。</p><p>心智模型的重要性。心智模型会影响我们的决定，进而影响代码的整体结构。如果一直做错误的大大小小的决定，那代码很快就会变成屎山。每个人的心智模型不可能完全一样，所以注定会做出不同的决定。对于团队而言，用框架和工具约束，让大家不做或少做决定是个很好的策略，比如用 prettier 统一编码风格。</p><p>文中有个例子。你写了一个组件，过了一周，产品迭代，而之前写的组件不能很好满足新需求。这时你有两个选择，A）思考之前的抽象是否正确，如果不正确，分解了重新做，B）增加一个额外 props，组件里加一些恶心的条件判断。你会如何选择？你会在乎之前投入的沉没成本还是面向未来考虑更多？其实没有对错，注意 By Scene。</p><p>自上而下 vs. 自下而上。「你可以自上而下或自下而上地构建。也就是说，你可以从构建层次结构中较高的组件开始。在比较简单的例子中，通常自上而下更容易，而在较大的项目中，自下而上更容易，并在构建过程中编写测试。」</p><p>自上而下是直观的、能快速出货的，大家通常也会这么干。当涉及到分解用户界面时，在功能区域周围画上方框，然后成为你的组件。这种功能分解的过程是自上而下的，通常会直接导致创建具有特定抽象性的专门组件。需求会改变。而在几个迭代过程中，这些组件很容易迅速变成单体巨石组件。</p><p>单体巨石组件有不少问题，包括 1）不容易复用子组件 2）包变大，比如 SSR 场景可能只希望渲染第一时间被用户看到的组件从而提速 3）rerender 问题导致运行时性能不好，也会让代码复杂，出现很多不必要的 memo 调用 4）不好的抽象导致项目复杂，迭代困难。「敏捷软件开发最重要的经验之一是迭代的价值；这在软件开发的各个层面都是正确的，包括架构。」</p><p>自下而上不那么直观，最初可能比较慢。因为这种方式会产生很多小组件，而实际中不是每个小组件在最初都需要可复用。所以前期需要花更多时间和努力，让复杂性被封装在每个小组件里。好处是长远看会更快，因为适应性更强。同时避免了单体巨石组件和前面介绍的他会带来的大量问题。</p><blockquote><p><a href="https://frontendmastery.com/posts/building-future-facing-frontend-architectures/" target="_blank" rel="noopener noreferrer">https://frontendmastery.com/posts/building-future-facing-frontend-architectures/</a></p></blockquote>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[7月17日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月17日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月17日内容汇总"/>
        <updated>2022-07-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Vite 3.0 正式版发布]]></summary>
        <content type="html"><![CDATA[<p>📒 Vite 3.0 正式版发布</p><p><a href="https://mp.weixin.qq.com/s/_GuGJaf8Sew5D8JaLQ3qOA" target="_blank" rel="noopener noreferrer">Vite 3.0 发布: 核心更新盘点与分析</a></p><p><a href="https://juejin.cn/post/7120820138907009060" target="_blank" rel="noopener noreferrer">Vite 3.0 正式发布，下一代前端构建工具！</a></p><blockquote><p><a href="https://vitejs.dev/blog/announcing-vite3.html#dev-improvements" target="_blank" rel="noopener noreferrer">https://vitejs.dev/blog/announcing-vite3.html#dev-improvements</a></p></blockquote><p>📒 nestjs + prisma 开发全栈项目</p><p><a href="https://www.prisma.io/docs/getting-started" target="_blank" rel="noopener noreferrer">https://www.prisma.io/docs/getting-started</a></p><p><a href="https://www.prisma.io/nestjs" target="_blank" rel="noopener noreferrer">https://www.prisma.io/nestjs</a></p><p>📒 <a href="https://juejin.cn/post/7115789691810480135" target="_blank" rel="noopener noreferrer">成为优秀的TS体操高手 之 TS 类型体操前置知识储备</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/8LxNZ0Hrne_EMZ352jmIXQ" target="_blank" rel="noopener noreferrer">如何在React中应用SOLID原则</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/b-qUPAXa31RqO7oFj3dReg" target="_blank" rel="noopener noreferrer">2022 年 CSS-in-JS 技术的又一匹黑马！</a></p><p>📒 <a href="https://juejin.cn/post/7119669717882634271" target="_blank" rel="noopener noreferrer">还在用命令行看日志？快用Kibana吧，可视化日志分析YYDS！</a></p><p>📒 <a href="https://juejin.cn/post/7119360791966384142" target="_blank" rel="noopener noreferrer">【面试造火箭，入职拧螺丝】万字详解如何从0开始手写一个Promise</a></p><p>⭐️ <a href="https://juejin.cn/book/7115598540721618944" target="_blank" rel="noopener noreferrer">Webpack5 核心原理与应用实践</a></p><p>📒 Webpack 特有的优化策略</p><p>由于 Webpack 出现的时候，还没有 ESM 规范，所以 Webpack 底层根据 CJS 规范实现 <code>__webpack_require__</code> 加载模块，这就导致 Webpack 打包会出现大量模板代码，增加打包后体积。相比之下，Rollup 基于 ESM 规范打包，产物代码就很干净。</p><p><strong>1. Scope Hoisting</strong></p><p>即 <code>作用域提升</code>，个人觉得这个应该是参考了 Rollup，但是 Webpack 的模块合并还是非常有限，必须是只引用了一次的模块才能合并，否则会造成模块冗余问题。</p><p>默认 <code>optimization.concatenateModules</code> 在生产环境下会启用：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">optimization</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">concatenateModules</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://webpack.docschina.org/plugins/module-concatenation-plugin/" target="_blank" rel="noopener noreferrer">https://webpack.docschina.org/plugins/module-concatenation-plugin/</a></p></blockquote><p><strong>2. 确定性模块 ID</strong></p><p>生产环境下，Webpack 的模块 ID 默认按模块解析顺序自增，即使源码没有修改，但是有时模块 ID 会发生变化，导致哈希改变，文件缓存失效。通过配置 <code>moduleIds: 'deterministic'</code> 有利于持久化缓存：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">optimization</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">moduleIds</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'deterministic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://webpack.docschina.org/configuration/optimization/#optimizationmoduleids" target="_blank" rel="noopener noreferrer">https://webpack.docschina.org/configuration/optimization/#optimizationmoduleids</a></p></blockquote><p><strong>3. Runtime Chunk</strong></p><p>运行时代码单独分包，一般 SPA 应用问题不大，多页应用打包，运行时代码单独分包可以配置持久化缓存。配置 <code>runtimeChunk: 'multiple'</code> 会为每一个 Initial Chunk 添加一个 Runtime Chunk，配置 <code>runtimeChunk: 'single'</code> 则会创建一个所有 Initial Chunk 共享的 Runtime Chunk：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">optimization</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">runtimeChunk</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'runtime'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://webpack.docschina.org/configuration/optimization/#optimizationruntimechunk" target="_blank" rel="noopener noreferrer">https://webpack.docschina.org/configuration/optimization/#optimizationruntimechunk</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/X1aL0qC3cslkwhThS6XidA" target="_blank" rel="noopener noreferrer">MySQL Redo Log 深入探索</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/UD0-7rWtOAxMuDpOR77gug" target="_blank" rel="noopener noreferrer">详解 Vite 依赖预构建流程</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/5dXLp7NjlpVsexOGTjbJ8A" target="_blank" rel="noopener noreferrer">VueUse scripts，他们都模仿过的脚本</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/bRlG5tc244ZVmPdb4mjbGQ" target="_blank" rel="noopener noreferrer">【第2669期】前端开发中的流程自动化与提效实践</a></p><p>📒 <a href="https://www.useanvil.com/blog/engineering/isolating-memory-leak-in-node/" target="_blank" rel="noopener noreferrer">隔离并修复 Node 应用程序中的内存泄漏</a></p><p>📒 <a href="https://juejin.cn/post/7119136400465330184" target="_blank" rel="noopener noreferrer">硬件加速中的“层”和层叠上下文中的“层”，是一个东西吗</a></p><p>📒 <a href="https://juejin.cn/post/7119123646471208968" target="_blank" rel="noopener noreferrer">《Go学习路线图》带你少走弯路，Let's Go ！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/zVSDbYFrRASnJCr2dJycDQ" target="_blank" rel="noopener noreferrer">前端原型链污染漏洞竟可以拿下服务器shell</a></p><p>📒 <a href="https://juejin.cn/post/7116448560568074270" target="_blank" rel="noopener noreferrer">我在 Shopee 工作这两年</a></p><p>📒 <a href="https://www.youtube.com/watch?v=JaM2rExmmqs" target="_blank" rel="noopener noreferrer">五个 React-Query 和 SWR 的小技巧</a></p><p>⭐️ ⭐️ <a href="https://juejin.cn/post/7118937685653192735" target="_blank" rel="noopener noreferrer">「React 进阶」 React 全部 Hooks 使用大全 （包含 React v18 版本 ）</a></p><p>📒 <a href="https://frontendmastery.com/posts/the-new-wave-of-react-state-management/" target="_blank" rel="noopener noreferrer">React 状态管理的新浪潮</a></p><p>⭐️ ⭐️ <a href="https://github.com/shfshanyue/fp-jargon-zh" target="_blank" rel="noopener noreferrer">函数式编程术语</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[7月10日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月10日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月10日内容汇总"/>
        <updated>2022-07-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 为什么 React 的 Diff 算法不采用 Vue 的双端对比算法]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7116141318853623839" target="_blank" rel="noopener noreferrer">为什么 React 的 Diff 算法不采用 Vue 的双端对比算法</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pT_tugg_EvE5pnMCaUqliw" target="_blank" rel="noopener noreferrer">Module Federation最佳实践</a></p><p>📒 <a href="https://juejin.cn/post/7117512204059934733" target="_blank" rel="noopener noreferrer">react18新特性及实践总结</a></p><p>📒 模块加载机制</p><p>commonjs 加载一个 module</p><p><code>webpack_require</code> -&gt; <code>vm.runInContext</code></p><p>📒 Nodejs Module Wrapper</p><p>Before a module's code is executed, Node.js will wrap it with a function wrapper that looks like the following:</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">exports</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> require</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> module</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __filename</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> __dirname</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Module code actually lives in here</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://nodejs.org/api/modules.html#the-module-wrapper" target="_blank" rel="noopener noreferrer">https://nodejs.org/api/modules.html#the-module-wrapper</a></p><p>📒 <a href="https://github.com/umijs/qiankun" target="_blank" rel="noopener noreferrer">微前端/qiankun</a></p><p>📒 <a href="https://juejin.cn/post/7089809919251054628" target="_blank" rel="noopener noreferrer">如何进阶TypeScript功底？一文带你理解TS中各种高级语法</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/B5Y_6fI94UItDkOj4gj9WA" target="_blank" rel="noopener noreferrer">【第2662期】低代码平台架构深度剖析</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fLHJ9AzcVbxXAZjQvIbvqQ" target="_blank" rel="noopener noreferrer">那些关于DOM的常见Hook封装（二）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/F4BotNoasCUnb-yWiB12sg" target="_blank" rel="noopener noreferrer">antd mobile 作者教你写 React 受控组件和非受控组件</a></p><p>📒 <a href="https://juejin.cn/post/7117051812540055588" target="_blank" rel="noopener noreferrer">我对 React 实现原理的理解</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/hHNnVlBCvnn19ciYRYNFAw" target="_blank" rel="noopener noreferrer">WebAssembly生态及关键技术综述</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Eovk2GT_noEOsH5BUwdlkA" target="_blank" rel="noopener noreferrer">HTTP3 RFC标准正式发布，QUIC会成为传输技术的新一代颠覆者吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XvX6b3i9D197s3voXRcemQ" target="_blank" rel="noopener noreferrer">如何将传统 Web 框架部署到 Serverless</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pxHGM-hOJISEoBHGZch5Ag" target="_blank" rel="noopener noreferrer">新来个技术总监，把 RabbitMQ 讲的那叫一个透彻，佩服！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/0xTZcE3MPezRl3LILR8a_w" target="_blank" rel="noopener noreferrer">关于前端主题切换的思考和现代前端样式的解决方案落地</a></p><p>⭐️ Data Flow in Remix</p><p>React 第一次和大家见面时，最引人注目的特点之一是他的「单向数据流」。这在官方文档 Thinking in React 里仍有介绍。用一句话概况即：UI 是状态的函数，或者叫 <code>ui=fn(state)</code>。</p><p>而后有不少遵从这种思想的数据流方案，比如 Redux、MobX 等，以 View -&gt; Action -&gt; State 这种循环的单向数据流方式进行。他们的缺点是这个数据流只在客户端运转，而一个应用通常还需要持久化数据和同步数据，这意味着还要有另一条数据流来和服务端做交互。</p><p>那有没有贯穿服务端和客户端的单向数据流？Remix！哈哈。Remix 将这一理念延伸到持久化数据的 API 层，通过 Loader 和 Action 把数据流串了起来，形成 Loader &gt; Component &gt; Action 的单向数据流。所以在 Remix 中，开发者也无需使用 Redux 等其他数据流方案。</p><p><a href="https://remix.run/blog/remix-data-flow" target="_blank" rel="noopener noreferrer">Data Flow in Remix</a></p><p><a href="https://mp.weixin.qq.com/s/fGaE_pGiC2BKKVKO0Fdj_g" target="_blank" rel="noopener noreferrer">MDH 前端周刊第 60 期：Fresh 1、SPA、框架流行度、1X 工程师、Father 4 RC</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/sqxRB63edItCT3vEzyJojA" target="_blank" rel="noopener noreferrer">巨石瓦解！我把Vue3巨石项目拆成了十几个微应用</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[7月3日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月3日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/7月3日内容汇总"/>
        <updated>2022-07-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 前端四种序列化]]></summary>
        <content type="html"><![CDATA[<p>📒 前端四种序列化</p><p><strong>1. JSON 序列化</strong></p><p>使用 <code>JSON.stringify()</code> 进行序列化，对应的 Content-Type 是 <code>application/json</code>。</p><p><strong>2. Query String 序列化</strong></p><p>使用 <code>new URLSearchParams()</code> 进行序列化，对应的 Content-Type 是 <code>application/x-www-form-urlencoded</code>。</p><blockquote><p>注意 URL query string 与 body 发送的 query string 略有不同，特别是对空格的处理</p></blockquote><p><strong>3. FormData 序列化</strong></p><p>使用 <code>new FormData()</code> 创建，对应的 Content-Type 是 <code>multipart/form-data</code>。</p><p><strong>4. XML 序列化</strong></p><p>使用 <code>new XMLSerializer()</code> 进行序列化，一般用于 DOM 对象。</p><p>📒 React 18 新特性</p><ul><li>Selective Hydration</li><li>Offscreen</li></ul><p>📒 <a href="https://juejin.cn/post/7115361618774622216" target="_blank" rel="noopener noreferrer">Vue 2.7 正式发布，代号为 Naruto</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/AyEb4fDsTvvfOG1Lgb1bzw" target="_blank" rel="noopener noreferrer">线上服务器老是卡，该如何优化</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/PGghgQfJTGIyoz8Bz8MD9A" target="_blank" rel="noopener noreferrer">【第2657期】前端JS攻防对抗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XCgZ5tOxyMKpOqvNvRDFQA" target="_blank" rel="noopener noreferrer">Redis 唯快不破的秘密</a></p><p>📒 新一代 npm 包构建工具 father 4 RC 发布</p><p>father 4 支持 Bundless 和 Bundle 两种构建模式。</p><ul><li>Bundless 指把所有源码文件单独编译、平行输出做发布。在 father 4 中，输出 ESModule 及 CommonJS 产物时会使用 Bundless 构建模式</li><li>Bundle 指把源码按 entry 打包成 1 个或多个文件做发布，也就是 Webpack 的打包模式。在 father 4 中，输出 UMD 及依赖预打包产物时会使用 Bundle 构建模式</li></ul><p>依赖预打包</p><ul><li>一是 NPM 包发布后安装体积更小、速度更快</li><li>二是不担心三方依赖更新引起 Bug</li><li>三是NPM 包发布后安装 0 warning</li></ul><p>不过，由于依赖中可能存在 <code>dynamic require/import</code> 等复杂的情况，现阶段不一定每个依赖都能顺利打包，father 4 会在 RC 阶段持续优化，将这项功能变得更加好用。</p><p><a href="https://mp.weixin.qq.com/s/zaFwGY-CztDUYTbIuaef1A" target="_blank" rel="noopener noreferrer">新一代 npm 包构建工具 father 4 RC 发布</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/gssYOb7xgSx2HsAeRGTgxA" target="_blank" rel="noopener noreferrer">【第2656期】使用 React Testing Library 的 15 个常见错误</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/q05JeUZ0mfjhhCshhhPNtw" target="_blank" rel="noopener noreferrer">【第2655期】携程基于 GraphQL 的前端 BFF 服务开发实践</a></p><p>📒 <a href="https://juejin.cn/post/7114177684434845727" target="_blank" rel="noopener noreferrer">聊聊 Vue 的双端 diff 算法</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/aPMJK-YYgsgUlm2x4uG3NQ" target="_blank" rel="noopener noreferrer">面试官：Vue的KeepAlive怎么实现的？我：这有啥好问的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Y_vtD5AlIry4anyy19Fhgw" target="_blank" rel="noopener noreferrer">如何优雅的写 Controller 层代码</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yluex5ufeJQ3eVyW9hD1-g" target="_blank" rel="noopener noreferrer">这些 hook 更优雅的管理你的状态</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-JtbeS01HEFhNCKYGExodg" target="_blank" rel="noopener noreferrer">干货 | Trip.com APP QUIC应用和优化实践</a></p><p>📒 <a href="https://juejin.cn/post/7113871265848360997" target="_blank" rel="noopener noreferrer">基于 qiankun 的微前端实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/A1LM8bWlcI8_fgUuCISU8w" target="_blank" rel="noopener noreferrer">[<!-- -->科普文<!-- -->]<!-- --> 浅谈 Function Programing 编程范式</a></p><p>📒 Taze - 一个让你的依赖保鲜的现代 cli 工具，支持定制、支持 monorepo</p><blockquote><p><a href="https://github.com/antfu/taze" target="_blank" rel="noopener noreferrer">https://github.com/antfu/taze</a></p></blockquote><p>📒 如何利用 Why、What、How 框架更好地写作</p><p>做项目时，要写三种类型的文档，单页文档、设计文档和 Review 文档，见图1，分别是写于启动前、实施前和完成后。单页文档写给老板看，介绍问题、预期结果、建议的解决方案和其他高层次的点；设计文档程序员可以理解为 RFC，写给同行或下属看，包含方法论、系统设计、实验结果等；Review 文档用于 Review 成功和失败的点。</p><p>文档怎么写？用「Why、What、How」的框架。听起来很简单，小学一年级老师也这么教，但作者的大部分文档都是用这个框架。Why 是让听众理解问题和背景，注意站在听众的角度，比如不要对着老板聊技术的 Why，也不要对着技术同学聊规划的 Why；What 讲解决方案是什么样子，以及可以做什么；How 讲如何实现 Why 和 What。</p><p>其中「Why」部分可以用 5 Why（<a href="https://en.wikipedia.org/wiki/Five_whys%EF%BC%89%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E8%BF%9E%E7%BB%AD%E9%97%AE" target="_blank" rel="noopener noreferrer">https://en.wikipedia.org/wiki/Five_whys）的方法，连续问</a> 5 个 Why，以便找出问题的根本原因。</p><p>此外还要注意「Who」，即你的听众是谁。为老板和为工程师写的文档差异会很大，因为不同人关注的点不同，前者更关心客户痛点、商业成果、投资回报率，后者更关心技术要求、设计选择、API 规范。</p><p>不同文档类型应用上述框架的例子见图 2。</p><p>文章内还有个金句，「Writing docs is expensive, but cheap.」文档很贵，需要花时间写、Review 和迭代，这些时间本可以花在写代码上。文档又很便宜，通过文档可以避免建立不靠谱的兔子洞项目，不靠谱的项目就算做出来也没人用，这个浪费是巨大的。所以，不要做「问题模糊、解决方案有争议」的项目。</p><blockquote><p><a href="https://eugeneyan.com/writing/writing-docs-why-what-how/" target="_blank" rel="noopener noreferrer">https://eugeneyan.com/writing/writing-docs-why-what-how/</a></p></blockquote><p>⭐️ <a href="https://juejin.cn/post/7113803250037424158" target="_blank" rel="noopener noreferrer">看懂 Lighthouse 中 Performance 核心指标</a></p><p>📒 <a href="https://juejin.cn/post/7113712658850775048" target="_blank" rel="noopener noreferrer">前端抢饭碗系列之Docker容器编排</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/_RmAH6p2lyzkhqLWw8cIKw" target="_blank" rel="noopener noreferrer">为什么 2022 年 ESM 又被发布了一次</a></p><p>📒 <a href="https://juejin.cn/post/7113732818663899166" target="_blank" rel="noopener noreferrer">漫谈 CSS 方法论</a></p><p>📒 <a href="https://juejin.cn/post/7113864980344078343" target="_blank" rel="noopener noreferrer">HTTP 新增的 103 状态码，这次终于派上用场了！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/v3lQpHBAIxhDmJ80w4CBcA" target="_blank" rel="noopener noreferrer">买啥高并发课程，白嫖不香么？（包括 PDF）</a></p><p>📒 <a href="https://juejin.cn/post/7113711538359238692" target="_blank" rel="noopener noreferrer">小程序长列表优化实践</a></p><p>📒 <a href="https://juejin.cn/post/7113586663741194247" target="_blank" rel="noopener noreferrer">前端食堂技术周刊第 42 期：Vue 2.7 Beta、TS 4.8 Beta、React 开源奖、ECMAScript 2022</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/4r1lFV1j7I0K0l5Ww3jj0g" target="_blank" rel="noopener noreferrer">封装一个管理 url 状态的 hook</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[6月26日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月26日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月26日内容汇总"/>
        <updated>2022-06-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 如何从微小细节着手，参与开源贡献]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/WAt4CNSqguCuaURHe5e4rQ" target="_blank" rel="noopener noreferrer">如何从微小细节着手，参与开源贡献</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Aa0tKO0A9IECRq2ZARyS-A" target="_blank" rel="noopener noreferrer">【第2650期】研发同学应该如何负责好一个项目</a></p><p>📒 <a href="https://juejin.cn/post/7112742451449692173" target="_blank" rel="noopener noreferrer">手写 Vue3 响应式系统：实现 computed</a></p><p>📒 <a href="https://juejin.cn/post/7112632005912690701" target="_blank" rel="noopener noreferrer">ECMAScript 2022 正式发布，有哪些新特性</a></p><p>📒 <a href="https://juejin.cn/post/7112212380397862926" target="_blank" rel="noopener noreferrer">手写 Vue3 响应式系统：核心就一个数据结构</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/jH4LU07Jor80E-S-v-Ba0Q" target="_blank" rel="noopener noreferrer">通过这两个 hook 回顾 Set/Map 基础知识</a></p><p>📒 React Hooks 使用注意事项</p><p>哪些变量应该放进依赖项里面：</p><ul><li>与视图渲染有关的变量，例如 <code>props</code>、<code>state</code>、<code>context</code></li><li>一些派生的状态，例如 <code>useCallback</code>、<code>useMemo</code> 的返回值</li></ul><p>哪些不应该放进依赖项里面：</p><ul><li>与视图渲染无关的变量，例如 <code>ref</code></li></ul><blockquote><p>这是因为 <code>useRef</code> 返回的引用在整个组件生命周期中保持不变，不存在闭包陷阱问题</p></blockquote><p>📒 React 性能优化策略</p><p>引起组件更新的因素：</p><ul><li>props（包括父组件 rerender 引起子组件 rerender）</li><li>state（在组件内部 <code>setState</code> 触发调度更新）</li><li>context（全局状态改变，通知订阅状态的组件更新）</li></ul><p>在不做任何优化的情况下，即使 props 没有改变，但是如果父组件 rerender，会导致子组件 props 对象重新生成，由于 React 默认的性能优化策略是 props <strong>严格相等比较</strong>，所以不可避免地导致子组件以及所有的子孙组件 rerender。</p><blockquote><p><strong>严格相等比较</strong> 高效但是难命中，只有当前组件没有 rerender 才能保证后续组件树都不 rerender</p></blockquote><p>使用了 <code>React.memo</code> 之后，会改为对 props 进行 <strong>浅比较</strong>，这样可以避免一些不必要的 rerender。</p><blockquote><p><strong>浅比较</strong> 容易命中但是有一定性能开销，因为需要遍历对象</p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/C5yeK40_PTz0Q-eLeyMvfQ" target="_blank" rel="noopener noreferrer">如何封装 cookie/localStorage/sessionStorage hook</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/uXJfgG52zGRedsy9bOqYYg" target="_blank" rel="noopener noreferrer">【第2648期】如何在 Vue 项目中，通过点击 DOM 自动定位VSCode中的代码行</a></p><p>📒 <a href="https://juejin.cn/post/7111507179881889800" target="_blank" rel="noopener noreferrer">HTTP史记 - 从HTTP/1到HTTP/3</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/UG4TlbADwQ5L9qxcS03x0Q" target="_blank" rel="noopener noreferrer">Umi 4 发布啦！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/kTKBlpuWCC6T1xuiQSulsw" target="_blank" rel="noopener noreferrer">记录第一次给开源项目提 PR</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/qG4MDeYGQJkZU4qSLj3JiA" target="_blank" rel="noopener noreferrer">Redis 高可用原理</a></p><p>📒 <a href="https://juejin.cn/post/7111485285652758535" target="_blank" rel="noopener noreferrer">如何移除你项目中99%的JS代码</a></p><p>📒 <a href="https://juejin.cn/post/7111201034264903688" target="_blank" rel="noopener noreferrer">浅谈前端项目里如何用 Logger 做好日志管理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/HjhkNP2eIWLxpLekPcSG8A" target="_blank" rel="noopener noreferrer">如何让定时器在页面最小化的时候不执行</a></p><p>📒 <a href="https://juejin.cn/post/7111120700768780301" target="_blank" rel="noopener noreferrer">一道有挑战性的 React Hook 场景题，考考你的功底</a></p><p>📒 <a href="https://juejin.cn/post/7111112135903543332" target="_blank" rel="noopener noreferrer">TypeScript 深水区：3 种类型来源和 3 种模块语法</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/lfV-7drnRjjNq65KxiT0gg" target="_blank" rel="noopener noreferrer">我为 Netty 贡献源码 | 且看 Netty 如何应对 TCP 连接的正常关闭，异常关闭，半关闭场景</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[6月19日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月19日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月19日内容汇总"/>
        <updated>2022-06-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 组件库开发新工具 Histoire]]></summary>
        <content type="html"><![CDATA[<p>📒 组件库开发新工具 Histoire</p><p>Vue 核心团队成员开发，底层基于 Vite，目测比 dumi 好用：</p><blockquote><p><a href="https://github.com/histoire-dev/histoire" target="_blank" rel="noopener noreferrer">https://github.com/histoire-dev/histoire</a></p></blockquote><p>📒 如何做好一个技术分享</p><p>最近有同事做了技术分享，发现了一些问题，在这里总结一下。</p><p>做技术分享也跟写文章一样，是有条理的，例如：</p><ul><li>先讲项目背景，现有方案存在哪些痛点（重点，技术不能为了用而用）</li><li>然后再讲讲怎么做技术选型的，有哪些竞品，各自优缺点，可以简单介绍实现原理（有自己的思考，而不是上级让你做 xx 预研就直接做了）</li><li>再讲团队中是如何落地的，实践过程中遇到哪些问题，是如何解决的，存量工程迁移方案（重点，节省其他同事的时间，避免重复踩坑）</li><li>最后可以总结一下，该方案落地相比现有方案提升的点，此外还存在哪些问题，在选型的时候需要重点考虑</li></ul><p>需要避免的几个点：</p><ul><li>避免开门见山，可以做一些必要的铺垫，以防有同事对相关技术不了解，为了理解你的内容，还得自己查资料</li><li>避免长篇大论都在讲底层架构、底层原理，没多少人会感兴趣，还不如多讲一下自己在实践过程中遇到哪些问题、怎么解决，有哪些心得体会，这样对别人帮助更大</li><li>避免内容空洞，例如讲了一大堆新特性，但都没有自己实践过，亦或是说各种性能好、各种优化，但没有实际的数据支撑，没有可以量化的指标、没有与竞品对比等等</li><li>搞清楚技术分享的目的，不是给其他同事上课，而是重在分享经验。可以是自己实践过程中踩了哪些坑，或者自己搭建了一套项目模板，可以直接开箱即用</li></ul><p>📒 执行 <code>yarn create</code> 命令背后做了哪些</p><p>执行 <code>yarn create &lt;starter-kit-package&gt;</code>，会先全局安装 <code>create-&lt;starter-kit-package&gt;</code>，如果已安装则会更新到最新版本，然后会执行 <code>bin</code> 字段中定义的脚本。</p><p>例如，<code>yarn create react-app my-app</code> 相当于：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">yarn</span><span class="token plain"> global </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> create-react-app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ create-react-app my-app</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/nRHlwYsr0MaadmaFWEIblQ" target="_blank" rel="noopener noreferrer">HTTP/3发布了，我们来谈谈HTTP/3</a></p><p>📒 <a href="https://github.com/GrowingGit/GitHub-Chinese-Top-Charts" target="_blank" rel="noopener noreferrer">GitHub中文排行榜</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/I1fHrRqZnZ7CdudFAmiNog" target="_blank" rel="noopener noreferrer">80%的Linux都不懂的内存问题</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QTP98PfkMg-C5OWXuQH4rg" target="_blank" rel="noopener noreferrer">十分钟带你入门 Web Components</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/l4z2fcNaCdoOHKKm0xqQYw" target="_blank" rel="noopener noreferrer">前端开发技术与业务的思考</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/egs426Y8x00BLhUdrcAOnw" target="_blank" rel="noopener noreferrer">【第2642期】基于 Serverless 的业务轻研发模式探索</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bI3rohCePnay2JVsQvdtfg" target="_blank" rel="noopener noreferrer">React新文档：不要滥用Ref哦</a></p><p>📒 <code>async</code> 函数注意事项</p><p>在 <code>async</code> 函数中，当有一个 <code>await</code> 后面的 Promise 状态变为 rejected，整个 <code>async</code> 函数执行就中断了。</p><p>这个在串行请求中非常有用。在很多场景下，我们需要将上一个请求返回的结果，作为参数进行下一次请求。假如上一个请求报错，那么结果自然获取不到，如果此时还进行下一个请求，这个逻辑显然有问题。因此，借助 <code>async</code> 函数的特性，在上一个请求报错的情况下，整个函数执行就断掉了，后续不会再发请求，无需手动进行异常处理。</p><p>📒 <a href="https://mp.weixin.qq.com/s/JkHur9_vKEVIg1hmp4yo0Q" target="_blank" rel="noopener noreferrer">我与Go的故事、我为什么推荐你学Go以及我的学习路线</a></p><p>📒 <a href="https://juejin.cn/post/7108719346947457054" target="_blank" rel="noopener noreferrer">CDN 为什么这么设计</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/7JnXUPmYRCYlWZoxop01ZA" target="_blank" rel="noopener noreferrer">Vue3.0 响应性原理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QmPwaX3xuMe6PA3o8VwI0A" target="_blank" rel="noopener noreferrer">一文读懂 TypeScript 泛型及应用</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/qeWNgqhAxb0_wA4Sqx3HKw" target="_blank" rel="noopener noreferrer">记录一次切换包管理器引发的血案</a></p><p>📒 <a href="https://juejin.cn/post/7108525565157589005" target="_blank" rel="noopener noreferrer">数据库表结构设计一点心得和经验</a></p><p>📒 2021-2022，我在大厂的前端最佳实践</p><p>monorepo 工具除了最基本的代码共享能力外，还应当至少具备三种能力，即：</p><ul><li>依赖管理能力。随着依赖数量的增加，依旧能够保持依赖结构的正确性、稳定性以及安装效率</li><li>任务编排能力。能够以最大的效率以及正确的顺序执行 Monorepo 内项目的任务（可以狭义理解为 npm scripts，如 build、test 以及 lint 等），且复杂度不会随着 Monorepo 内项目增多而增加</li><li>版本发布能力。能够基于改动的项目，结合项目依赖关系，正确地进行版本号变更、CHANGELOG 生成以及项目发布</li></ul><p><a href="https://mp.weixin.qq.com/s/AQ8tTMIbxkG98xiMPuttPw" target="_blank" rel="noopener noreferrer">2021-2022，我在大厂的前端最佳实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/I8WurtOeS_u2d5RAO4dukg" target="_blank" rel="noopener noreferrer">Ramda 哪些让人困惑的函数签名规则</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Iu7PotYFwjXyFPka-So6Qw" target="_blank" rel="noopener noreferrer">Github上8个很棒的React项目</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/B-HkMjn6dKKw4JFjANjUxQ" target="_blank" rel="noopener noreferrer">全网最强 JVM 来袭</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/iGtIW7Sz9IiX-c7oBWdFEg" target="_blank" rel="noopener noreferrer">useEffect 怎么支持 async...await</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[6月12日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月12日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月12日内容汇总"/>
        <updated>2022-06-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 【第2638期】前端安全之 CSRF 攻击原理和防护方法]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/MSK1f6qEAB75iiYzHWhlgA" target="_blank" rel="noopener noreferrer">【第2638期】前端安全之 CSRF 攻击原理和防护方法</a></p><p>📒 何时发起 fetch 请求？试试在 React Router 中吧</p><p>这是一则近期在 Reactathon 中的演讲。Remix 创始人之一的 Ryan Florence 极力推荐了在 React Router 中去做 fetch 请求。</p><blockquote><p><a href="https://www.youtube.com/watch?v=95B8mnhzoCM" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=95B8mnhzoCM</a></p></blockquote><p>📒 React Route v6.4 版本已进入预发布阶段</p><blockquote><p><a href="https://github.com/remix-run/react-router/releases/tag/v6.4.0-pre.2" target="_blank" rel="noopener noreferrer">https://github.com/remix-run/react-router/releases/tag/v6.4.0-pre.2</a></p></blockquote><p>📒 最新一期的 20minJS 请来了 Mark Erikson，主要讨论了 状态管理以及 Redux Toolkit</p><blockquote><p><a href="https://podcast.20minjs.com/1952066/10665172-episode-12-redux-toolkit-and-state-management-in-react-with-mark-erikson" target="_blank" rel="noopener noreferrer">https://podcast.20minjs.com/1952066/10665172-episode-12-redux-toolkit-and-state-management-in-react-with-mark-erikson</a></p></blockquote><p>📒 Storybook v6.5 版发布：旨在提升生产力的新工作流</p><p>这款流行的组件开发工具库本次发布了许多新功能，包括在浏览器中验证用户行为的交互测试，一个将 story 和 variant 连结起来的 Figma 插件以及引入了 Webpack 5 的惰性编译用来提高启动速度等。</p><blockquote><p><a href="https://storybook.js.org/blog/storybook-6-5/" target="_blank" rel="noopener noreferrer">https://storybook.js.org/blog/storybook-6-5/</a></p></blockquote><p>📒 Glide Data Grid v4.0 版发布：一款高效的 React 数据网格库 </p><p>它自称是一款“毫不妥协，速度飞快的数据网格”。它支持高达百万条数据的多样化渲染，且支持 TypeScript。主页上还有一个简洁的 Demo，它支持 MIT 许可证。详情请看 GitHub 仓库。</p><blockquote><p><a href="https://grid.glideapps.com/" target="_blank" rel="noopener noreferrer">https://grid.glideapps.com/</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/Q2Dx45dOnqrwthllOEahDg" target="_blank" rel="noopener noreferrer">开发一个浏览器插件从未如此简单</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/dVD22v_phrk4Xl2GQH_-yw" target="_blank" rel="noopener noreferrer">深入浅出 npm &amp; yarn &amp; pnpm 包管理机制</a></p><p>📒 pkg.land：发现 npm 包的替代品的方式</p><blockquote><p><a href="https://pkg.land/" target="_blank" rel="noopener noreferrer">https://pkg.land/</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7073001183123603470" target="_blank" rel="noopener noreferrer">平时的工作如何体现一个人的技术深度？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fxX4oPHURDpvFvCIZUd7VA" target="_blank" rel="noopener noreferrer">关于前端大管家 package.json，你知道多少？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bR7vDw_ii4VPL4f8YVIWEg" target="_blank" rel="noopener noreferrer">【第2636期】从"微前端"到“微模块”</a></p><p>📒 <a href="https://juejin.cn/post/7104301566857445412" target="_blank" rel="noopener noreferrer">你还在直接用 localStorage 么？该提升下逼格了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Roca8dPlP5H8z1JIaCGuHA" target="_blank" rel="noopener noreferrer">ahooks 中那些控制“时机”的hook都是怎么实现的？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pS-pLnG4RLMtodvvqmzEUw" target="_blank" rel="noopener noreferrer">实现一个实时预览的 json 编辑器组件（react 版）</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/524973511" target="_blank" rel="noopener noreferrer">微信团队分享：微信后台在海量并发请求下是如何做到不崩溃的</a></p><p>📒 <a href="https://juejin.cn/post/6844903489970126856" target="_blank" rel="noopener noreferrer">使用 <code>-force</code> 被认为是有害的；了解 Git 的 <code>-force-with-lease</code> 命令</a></p><p>📒 <a href="https://juejin.cn/post/7105993870185332766" target="_blank" rel="noopener noreferrer">使用 Three.js 实现"雪糕"地球，让地球也凉爽一夏</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/cOTxpimRvv18HIiLaneuEQ" target="_blank" rel="noopener noreferrer">从0到1带你用webpack 5构建monorepo项目——上篇</a></p><p>📒 content-visibility 再探究，完美替代 Lazyload？</p><p>直接看结论：</p><ul><li>在一些需要被频繁切换显示、隐藏状态的元素上，使用 <code>content-visibility: hidden</code>，用户代理无需重头开始渲染它和它的子元素，能有效地提升切换时的渲染性能；</li><li><code>content-visibility: auto</code> 的作用更加类似于虚拟列表，使用它能极大地提升长列表、长文本页面的渲染性能；</li><li>合理使用 <code>contain-intrinsic-size</code> 预估设置了 <code>content-visibility: auto</code> 元素的高宽，可以有效避免滚动条在滚动过程中的抖动；</li><li><code>content-visibility: auto</code> 无法直接替代 LazyLoad，设置了 <code>content-visibility: auto</code> 的元素在可视区外只是未被渲染，但是其中的静态资源仍旧会在页面初始化的时候被全部加载；</li><li>即便存在设置了 <code>content-visibility: auto</code> 的未被渲染的元素，也并不会影响全局的搜索功能。</li></ul><p><a href="https://mp.weixin.qq.com/s/bZ6edmEoVXLWloQssiQxRg" target="_blank" rel="noopener noreferrer">content-visibility 再探究，完美替代 Lazyload？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DhkQNO8Hv1zZP9Fu7uSw-g" target="_blank" rel="noopener noreferrer">冷知识！使用 display: contents 实现幽灵节点？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JxrCUN8PQ_xG_AkfV-G5FQ" target="_blank" rel="noopener noreferrer">基于 Vue3 和 TypeScript 项目大量实践后的思考</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/t3nBYybInY_AXVpbeKi6Jw" target="_blank" rel="noopener noreferrer">ahooks 是怎么解决用户多次提交问题？</a></p><p>📒 <a href="https://juejin.cn/post/6953867408096362503" target="_blank" rel="noopener noreferrer">这还是我最熟悉的package.json吗？</a></p><p>📒 <a href="https://juejin.cn/post/6950817077670182943" target="_blank" rel="noopener noreferrer">npm init @vitejs/app的背后，仅是npm CLI的冰山一角</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/QZ49KF-k14NamqlF_hBT9A" target="_blank" rel="noopener noreferrer">不到 100 行代码，实现 React Router 核心逻辑</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/z6rWffzjeww5GRZVh6hK8Q" target="_blank" rel="noopener noreferrer">ahooks 是怎么解决 React 的闭包问题的？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/k2LYtZ6lU5CH1_grlKQT0Q" target="_blank" rel="noopener noreferrer">如何使用插件化机制优雅的封装你的请求hook</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/_lKKAvzVQPTQ5FeKBF6hRA" target="_blank" rel="noopener noreferrer">【第2633期】JavaScript运行时环境和标准</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/9TnD_oXnjiU8aoQJBzLbsA" target="_blank" rel="noopener noreferrer">TS 的 esModuleInterop 与 allowSyntheticDefaultImports 配置</a></p><p>📒 NPM 发包脚本加上下面这段代码</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">npmPublish</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> scripts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"npm set-script postinstall \"\""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"npm publish"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"npm set-script postinstall \"patch-package\""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> scripts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">prev</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> script</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> prev</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">runScript</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">script</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token known-class-name class-name">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>这里的 <code>reduce()</code> 确保了 Promise 按顺序调用，而 <code>Promise.all()</code> 并发执行不保证顺序</p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/LMSveysC0re7A0sbvvImuw" target="_blank" rel="noopener noreferrer">【第2632期】微前端框架 Satum 的性能优化策略</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/lApEUTzOsdbvMeRUXcTneg" target="_blank" rel="noopener noreferrer">大家都能看得懂的源码（一）ahooks 整体架构篇</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/h7GiH_s8e8wM0CDS_tF_3w" target="_blank" rel="noopener noreferrer">React新文档：不要滥用effect哦</a></p><p>📒 <a href="https://juejin.cn/post/7103165205483356168" target="_blank" rel="noopener noreferrer">你还不会写 vite 插件吗？没关系，我教你啊</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Gl94ISY5N4BYyYmVT9-QFQ" target="_blank" rel="noopener noreferrer">用 Node.js 手写一个 DNS 服务器</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[6月5日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月5日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/6月5日内容汇总"/>
        <updated>2022-06-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 为什么不建议用 switch...case 实现策略模式]]></summary>
        <content type="html"><![CDATA[<p>📒 为什么不建议用 <code>switch...case</code> 实现策略模式</p><p>相比 <code>if...else</code> 来说，<code>switch...case</code> 已经有了明显提升，但还是不适合用来编写策略模式。</p><p>这是因为 <code>switch...case</code> 实际上违背了 <strong>开闭原则</strong>，即对扩展开放，对修改封闭。例如当我们需要增加规则的时候，就需要靠修改代码来实现。</p><p>从这一点来说，用 JS 对象或者 Map 对象来实现策略模式就要灵活很多，可以动态扩展规则。</p><p>📒 <a href="https://mp.weixin.qq.com/s/QWwb8PXtdJJUKyicHRmBkw" target="_blank" rel="noopener noreferrer">干货 | 携程机票前端Svelte生产实践</a></p><p>📒 <a href="https://juejin.cn/post/7072591716678795301" target="_blank" rel="noopener noreferrer">通过 Preact 看 Diff 算法细节</a></p><p>📒 Vite 打包流程</p><p>首先调用 <code>rollup</code> 方法（Rollup 的编程式 API）编译出 <code>bundle</code> 添加到 <code>build</code> 数组中，接下来就是遍历它，进行 <code>bundle</code> 的写操作（即输出到硬盘上），因为 vite 使用的是 Rollup 完成文件的打包，所以这里调用的是 <code>bundle.write</code> 来将文件输出到硬盘上。</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">packages/vite/src/node/build.ts</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> build </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> builds</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> bundle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> build</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">bundle</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> output </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> bundle</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">write </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'write'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'generate'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    dir</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> resolvedAssetsPath</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    format</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'es'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    sourcemap</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    entryFileNames</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">[name].[hash].js</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    chunkFileNames</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">[name].[hash].js</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    assetFileNames</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">[name].[hash].[ext]</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">...</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rollupOutputOptions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  build</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">html </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">renderIndex</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">output</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  build</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">assets </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> output</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> postBuildHooks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queue</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hook</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> queue</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hook</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">build </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token builtin">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>注意 Vite 2.x 源码结构稍有不同，但是整体流程还是类似的：</p><p><a href="https://github.com/vitejs/vite/blob/ab23e6e7b490cf610a4465cc533f671a729fdfa8/packages/vite/src/node/build.ts#L543" target="_blank" rel="noopener noreferrer">https://github.com/vitejs/vite/blob/ab23e6e7b490cf610a4465cc533f671a729fdfa8/packages/vite/src/node/build.ts#L543</a></p></div></div><p>这里有一个值得学习的地方，这边 <code>postBuildHooks</code> 的类型定义是 <code>((build: any) =&gt; Promise&lt;any&gt;)[]</code>，如何保证调用顺序，即上一次调用完成后进行下一次调用？</p><p>通常我们用 <code>reduce</code> 做管道操作都是不能用于 Promise，因为管道操作需要将上一次调用的返回值，作为参数传入下一次调用，但 Promise 的话很可能是 <code>pending</code>，根本拿不到上一次调用的返回值。所以一般来说我们只能将 <code>reduce</code> 改成普通 <code>FOR</code> 循环：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> initialValue </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> hooks </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> postBuildHooks</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  initialValue </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hook</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">build</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>而源码中对 <code>reducer</code> 函数进行了包装，将 <code>hook</code> 的执行放到 <code>then</code> 方法回调中，这样就可以保证调用顺序：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> postBuildHooks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queue</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hook</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> queue</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hook</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">build </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token builtin">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://juejin.cn/post/6889589799687028750" target="_blank" rel="noopener noreferrer">vite 不支持 ie 11？configureBuild Hook 帮你定制 bundle 打包过程</a></p><p>📒 VS Code 如何快速定位到问题代码</p><p>在 TS 项目中，经常会因为类型问题出现报错，因此需要快速定位到问题代码。</p><p>在 VS Code 中可以使用 <code>Ctrl + Shift + M</code> 快捷键打开问题面板，可以看到当前文件中所有的 errors 和 warnings。此时，按 <code>F8</code> 可以依次跳转查看当前文件中的问题。</p><p>📒 <a href="https://juejin.cn/post/7104460511869141006" target="_blank" rel="noopener noreferrer">20个GitHub仓库助你成为React大师</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/llLKRCOLvZSjSO4WfzBgPg" target="_blank" rel="noopener noreferrer">从零开始实现一个简单的低代码编辑器</a></p><p>⭐️ <a href="https://juejin.cn/post/7069772395610898462" target="_blank" rel="noopener noreferrer">从arco-design的collapse组件分析如何吸收开源项目的知识</a></p><p>📒 <a href="https://juejin.cn/post/7101457212085633054" target="_blank" rel="noopener noreferrer">模块联邦浅析</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yu1tKtwneoTI9eSGS4us-g" target="_blank" rel="noopener noreferrer">我们是怎么在项目中落地qiankun的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/dSAitXlbLpnsM9uobezyhQ" target="_blank" rel="noopener noreferrer">【第2631期】浅谈 Atomic CSS 的发展背景与 Tailwind CSS</a></p><p>📒 通过 JS 运行时堆快照进行 Web 爬虫</p><p>当网站提供的接口无法满足需求的时候（甚至可能连接口都没有），爬虫可能是一种不太理想的解决方案。虽然 Puppeteer 和 Playwright 使控制无头浏览器变得容易，但是获取你需要的数据，还是会很复杂。如果你可以从网站的页面堆中提取数据呢？Puppeteer Heap Snapshot 是这个实验的最终结果。</p><blockquote><p><a href="https://www.adriancooney.ie/blog/web-scraping-via-javascript-heap-snapshots" target="_blank" rel="noopener noreferrer">https://www.adriancooney.ie/blog/web-scraping-via-javascript-heap-snapshots</a></p></blockquote><p>📒 JS 清空数组的方式</p><p>以下两种清空数组的方式有何区别：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> arr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token spread operator" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这种是 immutable 的方式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 即创建一个空数组，用该空数组指针替换原数组的指针</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 不影响其他引用原数组内存地址的变量</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">arr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这种是 mutable 的方式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 即直接修改原数组，不创建新数组，仍然是原数组指针</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 会影响其他引用原数组内存地址的变量</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/ULY-_Vq-Jgb8aCbhyfqYHw" target="_blank" rel="noopener noreferrer">【零基础】充分理解WebGL（三）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/EvkMQCPwg-B0fZonpwXodg" target="_blank" rel="noopener noreferrer">Go Error 处理最佳实践</a></p><p>📒 Map 对象小技巧</p><p>Map 对象可以记住键值对插入顺序，那么如何获取顺序呢？答案是通过迭代器接口。然后迭代器接口可以直接遍历，也可以转为数组，这样就变成获取数组第一个元素了。</p><blockquote><p>按照这个思路，实际上也可以用 Map 实现队列</p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/ROwTG6AC2pK5UN1dzY5x8w" target="_blank" rel="noopener noreferrer">Web3.0开发入门</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DswfPb6J1w2B_MWj1TjyOg" target="_blank" rel="noopener noreferrer">从源码中来，到业务中去，React性能优化终极指南</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/l19wbHNIrhjyD0HwJwuvmQ" target="_blank" rel="noopener noreferrer">剖析React核心设计原理—Virtual Dom</a></p><p>📒 <a href="https://juejin.cn/post/7102360505313918983" target="_blank" rel="noopener noreferrer">前端工程化：保姆级教学 Jenkins 部署前端项目</a></p><p>📒 <a href="https://juejin.cn/post/7104152252180332581" target="_blank" rel="noopener noreferrer">正则表达式完整指南</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/b15cyyg53lVKQ_TtR8hugQ" target="_blank" rel="noopener noreferrer">【第2630期】javascript中的依赖注入</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/sEvP3nLUOBwbSHP9mmT__A" target="_blank" rel="noopener noreferrer">【前端部署附录一】写给前端的 docker 使用指南</a></p><p>📒 Chrome 如何调试移动端 H5 页面</p><blockquote><p>chrome://inspect/#devices</p></blockquote><p>📒 支付宝体验科技 Umi 系列文章</p><p><a href="https://www.yuque.com/antfe/featured/uf1bok" target="_blank" rel="noopener noreferrer">Umi 4 特性 05：稳定白盒性能好的 ESLint</a></p><p>📒 如何回滚 Git 分支代码</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 找到需要回滚的版本哈希，执行 git reset</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> reset --hard HEAD^</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 然后强制 push</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> push -f -u origin pre</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://zhuanlan.zhihu.com/p/137856034" target="_blank" rel="noopener noreferrer">拜托，不要再问我Git如何回滚代码</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Sz8u6lzkL1nnpRxGrdbYJg" target="_blank" rel="noopener noreferrer">如何华丽的实现一套脚手架 - 以umicli和转转zzcli为例</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ZTI-8RI0l314Ki9oBxqRWw" target="_blank" rel="noopener noreferrer">深入浅出 npm &amp; yarn &amp; pnpm 包管理机制</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/LL6VZj36PKftbwaybBFmXg" target="_blank" rel="noopener noreferrer">一文带你进入微前端世界</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/R6Xr8SoJicZB8-P4H2SSPA" target="_blank" rel="noopener noreferrer">你还在手动部署埋点吗？从0到1开发Babel埋点自动植入插件</a></p><p>📒 一个三小时的 React Native 速成课</p><blockquote><p><a href="https://www.youtube.com/watch?v=VozPNrt-LfE" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=VozPNrt-LfE</a></p></blockquote><p>📒 使用 Three.js：一款流行的 3D JavaScript 库</p><blockquote><p><a href="https://betterprogramming.pub/working-with-three-js-the-popular-3d-javascript-library-bd2e9b03c95a?gi=8c31e429644f" target="_blank" rel="noopener noreferrer">https://betterprogramming.pub/working-with-three-js-the-popular-3d-javascript-library-bd2e9b03c95a?gi=8c31e429644f</a></p></blockquote><p>📒 Next.js 后续规划的 RFC：即将到来的重大变化</p><blockquote><p><a href="https://nextjs.org/blog/layouts-rfc" target="_blank" rel="noopener noreferrer">https://nextjs.org/blog/layouts-rfc</a></p></blockquote><p>📒 2022 年 React 状态管理库综述</p><p>React 的优势在于它可以灵活地适应不同的开发方式，其中也包括状态管理方面。这篇文章总结了几个流行的状态管理库，包括 Zustand、Recoil（来自 Facebook）、XState，当然还有 Redux。</p><blockquote><p><a href="https://www.albertgao.xyz/2022/02/19/react-state-management-libraries-2022/" target="_blank" rel="noopener noreferrer">https://www.albertgao.xyz/2022/02/19/react-state-management-libraries-2022/</a></p></blockquote><p>📒 <a href="https://www.yuque.com/surfacew/fe/qg0uev" target="_blank" rel="noopener noreferrer">深入浅出前端做控制反转与依赖注入</a></p><p>⭐️ ⭐️ 现代 Monorepo 工程技术选型，聊聊我的思考</p><p>总结一下：</p><ul><li>使用 PNPM 作为 monorepo 项目的包管理工具</li><li>使用 Changesets 作为 monorepo 项目的发包工具</li><li>使用 Turborepo 作为 monorepo 项目多包任务执行工具</li></ul><p><a href="https://mp.weixin.qq.com/s/99nozy-vtFMGcBTxYvumWA" target="_blank" rel="noopener noreferrer">现代 Monorepo 工程技术选型，聊聊我的思考</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/T5vXADH4nXqAxyDcKWE64Q" target="_blank" rel="noopener noreferrer">MySQL 主从，6 分钟带你掌握</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1HyQLZcnZN6I27p_hbfUPg" target="_blank" rel="noopener noreferrer">【第2628期】基于设计稿识别的可视化低代码系统实践</a></p><p>📒 <a href="https://juejin.cn/post/7098211898990002207" target="_blank" rel="noopener noreferrer">前端配置化真香～上班又多了60%的摸🐟时间</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[5月29日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月29日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月29日内容汇总"/>
        <updated>2022-05-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 如何将数组转为对象]]></summary>
        <content type="html"><![CDATA[<p>📒 如何将数组转为对象</p><p>之前在业务中遇到一个场景，配置 Webpack alias 的时候，会出现很多模板代码：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">resolve</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">alias</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"@"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"src"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"@foo"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"src/foo"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string-property property" style="color:#36acaa">"@bar"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"src/bar"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>那么其实是可以通过数组的方式干掉模板代码：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">constructAlias</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arr</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fromEntries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cwd</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">replace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex" style="color:#36acaa">^\@(.*?)$</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'$1'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'@'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@foo'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'@bar'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">constructAlias</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>使用数组的 <code>map</code> 方法映射出一个 entry 数组，可以表示为形如 <code>[key, value][]</code> 的结构，然后使用 <code>Object.fromEntries</code> 将 entry 数组转为对象</p></blockquote><p>这里需要注意，<code>Object.fromEntries</code> 是 ES2019 语法，支持 Chrome &gt;= 73 和 Node.js &gt;= 12.0.0。浏览器环境问题不大，一般都会配置 Babel polyfill 兼容，但是 Node.js 环境就会出一些问题，例如一些 CI 环境的 Node.js 版本很老，就会报错进而导致构建失败。因此通常开发的话，我们应该尽量用数组的 <code>reduce</code> 替代：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">constructAlias</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arr</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">accu</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    accu</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cwd</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">replace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex" style="color:#36acaa">^\@(.*?)$</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'$1'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> accu</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 An introductory guide to Contiuous Integration and Delivery/Deployment (CI/CD) for Frontend Developers</p><blockquote><p><a href="https://blog.tegadev.xyz/an-introductory-guide-to-ci-cd-for-frontend-developers" target="_blank" rel="noopener noreferrer">https://blog.tegadev.xyz/an-introductory-guide-to-ci-cd-for-frontend-developers</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/JUXz9TOKbkO1oAzHjVfwnQ" target="_blank" rel="noopener noreferrer">基于设计稿识别的可视化低代码系统实践</a></p><p>📒 <a href="https://juejin.cn/post/7102328973820067877" target="_blank" rel="noopener noreferrer">被diss性能差，Dan连夜优化React新文档</a></p><p>📒 <a href="https://juejin.cn/post/7102233142567632933" target="_blank" rel="noopener noreferrer">Node.js 调试一路走来经历了什么</a></p><p>📒 如何解决组件库打包条件引入</p><p>由于 <code>import</code> 语句必须放在顶层，不能放在条件判断中。如果同时保留两个 <code>import</code> 语句则会导致两个包都被打包进去。所以解决的方案就是在构建阶段动态修改 <code>import</code> 语句，但是需要注意两个问题：</p><ul><li>要注意修改时机，假如打包工具依赖分析已经完成，这时候再修改就太迟了</li><li>另外还要注意不同打包工具的兼容性，如果开发 rollup 插件，可能导致 webpack、vite 等工具不兼容</li></ul><p>因此选择开发 babel 插件，可以兼容各种打包工具。</p><p>📒 <a href="https://mp.weixin.qq.com/s/4cZ3rJz4P5bSRSeXDbFoMQ" target="_blank" rel="noopener noreferrer">UMI3源码解析系列之运行时插件机制</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/g1fr1fnGspi7SETyP9B6rA" target="_blank" rel="noopener noreferrer">推荐一个前端技术选型神器</a></p><p>📒 Webpack 模块构建缓存</p><p>模块构建缓存，推荐使用 Webpack5 的 <code>filesystem cache</code>，技术更成熟，可以参考 CRA 的 Webpack 配置：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">cache</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'filesystem'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">version</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createEnvironmentHash</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">raw</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">cacheDirectory</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> paths</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">appWebpackCache</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">store</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'pack'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">buildDependencies</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">defaultWebpack</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'webpack/lib/'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">config</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">__filename</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">tsconfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">paths</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">appTsConfig</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> paths</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">appJsConfig</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">f</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">existsSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>关于持久化缓存，有两个地方需要注意：</p><ul><li>默认缓存的路径是 <code>node_modules/.cache/webpack</code>，也就是说，只要删除 <code>node_modules</code>，相当于缓存也被清空了</li><li>本地和 CI 环境的缓存是相互独立的，本地的缓存无法在 CI 环境使用。在 CI 环境中需要使用 CI 的缓存机制</li></ul><blockquote><p><a href="https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js" target="_blank" rel="noopener noreferrer">https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/2OXIGB5qQFc2isIxhm33bg" target="_blank" rel="noopener noreferrer">最高性能的包管理器-pnpm</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/dtmYRsThI3o_a7AWnxFkDw" target="_blank" rel="noopener noreferrer">【第2624期】Fastify 如何实现更快的 JSON 序列化</a></p><p>📒 如何设置 npm 私有源</p><p>在项目根目录建一个 <code>.yarnrc</code> 文件，配置如下：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 淘宝源</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token assign-left variable" style="color:#36acaa">registry</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">https://registry.npmmirror.com</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 私有源</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">@myscope:registry</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">https://mycustomregistry.example.org</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这样的话，<code>package.json</code> 中带有 <code>@myscope</code> 前缀的依赖，例如 <code>@myscope/design-system</code> 都会从私有源下载。</p><p>📒 <a href="https://juejin.cn/post/7101608088100143118" target="_blank" rel="noopener noreferrer">前端多线程编程探索</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pSoSpuLXfeghfMvEfl38WA" target="_blank" rel="noopener noreferrer">精妙的配合！文字轮播与图片轮播？CSS 不在话下</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3yy9V5HMDWPFwEf1cyL-lw" target="_blank" rel="noopener noreferrer">并发渲染优化：让文件树的渲染又快又稳</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2MsgPh9AZtUoJpsLLdOynQ" target="_blank" rel="noopener noreferrer">UMI3源码解析系列之构建原理</a></p><p>⭐️ 看了9个开源的 Vue3 组件库，发现了这些前端的流行趋势</p><p>对包管理器的总结非常好，推荐看一下。</p><p><strong>npm@v3 之前</strong></p><ul><li>嵌套结构（nest），会出现大量重复装包的问题</li><li>因为是树型结构，<code>node_modules</code> 嵌套层级过深，导致文件路径过长</li><li>模块实例不能共享，例如在两个不同包引入的 React 不是同一个模块实例</li></ul><p><strong>npm@v3 / yarn</strong></p><ul><li>分身依赖：npm@v3 使用扁平化（flat）的方式安装依赖，一定程度上解决了重复装包的问题，但是注意并没有完全解决，例如 A 和 B 依赖了不同版本的 C，会导致 C 被安装两次</li><li>幽灵依赖：由于使用扁平化方式安装，<code>package.json</code> 里并没有写入的包竟然也可以在项目中使用了</li><li>平铺减少安装没有减省时间，因为扁平化算法比较复杂，时间居然还增加了</li></ul><p><strong>npm@v5 / yarn</strong></p><p>该版本引入了一个 <code>lock</code> 文件，以解决 <code>node_modules</code> 安装中的不确定因素。这使得无论你安装多少次，都能有一个一样结构的<code>node_modules</code>。</p><p>然而，平铺式的算法的复杂性，幽灵依赖之类的问题还是没有解决。</p><p><a href="https://juejin.cn/post/7092766235380678687" target="_blank" rel="noopener noreferrer">看了9个开源的 Vue3 组件库，发现了这些前端的流行趋势</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/yxsiWiZi08B5tC3Ab7DKWg" target="_blank" rel="noopener noreferrer">Node.js Web 框架 Midway 入门实战</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/jU0awhez7QzN_nKrm4BNwg" target="_blank" rel="noopener noreferrer">肝了一个月的 DDD，一文带你掌握</a></p><p>📒 使用 rollup 构建第三方库包括哪些过程</p><ul><li>浏览器不兼容的语法转换<ul><li>Vue 文件处理：<code>rollup-plugin-vue</code></li><li>JSX、TS 语法编译：<code>rollup-plugin-babel</code></li><li>支持 CSS 加载、添加前缀、压缩、scss/less 预编译：<code>rollup-plugin-postcss</code></li></ul></li><li>编译兼容<ul><li>仅限语法转换，不建议 polyfill：<code>rollup-plugin-babel</code></li></ul></li><li>混淆压缩<ul><li>对应：<code>rollup-plugin-terser</code></li></ul></li><li>打包为一份文件（注意 <code>peerDependencies</code> 外部化），多种打包格式，生成类型声明文件等</li><li>工程质量保障，例如 ESLint、TS 类型检查、单元测试等</li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>前面两步可以避免业务项目的 <code>babel-loader</code> 处理 <code>node_modules</code> 下的模块，提升构建效率。</p></div></div><p>📒 如何实现主题切换</p><p>关键看场景，如果需要在运行环境动态切换，就需要打包两套样式，然后通过媒体查询之类的方式进行切换。如果不需要动态切换，可以在构建的时候进行变量注入。</p><p>自己开发的组件库是否有必要设置主题？样式都不打包，less 变量注入肯定没用的；如果搞个 <code>theme-reset.less</code>，肯定会污染到全局。最好还是在业务工程里面设置主题。</p><p>📒 如何做首屏性能优化</p><p><strong>1. 路由懒加载</strong></p><p>首先想到的就是解决资源冗余问题，我们可以按需投喂 JS 资源，只把渲染当前页面需要的资源投喂给浏览器，对应的方案是路由懒加载。</p><p><strong>2. 分包优化</strong></p><p>在按需投喂 JS 资源的基础上，对于一些不需频繁修改、体积又很大的依赖进行拆包处理，例如 <code>react</code>、<code>react-dom</code>，单独分包设置强缓存。</p><p><strong>3. 服务端渲染</strong></p><p>如果按需投喂 JS 资源还是太慢，可以考虑服务端渲染（SSR），在服务端直接把当前页面的 HTML 丢给浏览器，可以理解为按需投喂 HTML 页面。</p><p><strong>4. 静态生成 &amp;&amp; 混合渲染</strong></p><p>服务端渲染可以理解为在服务端调接口渲染出 HTML 丢给浏览器，但是这个过程还是存在性能开销。对于一些不需要动态数据的页面，例如文档、博客等，可以考虑静态生成（SSG），即在构建的时候就渲染出 HTML，可以极大提升首屏性能，当然更多时候是 SSG 和 SSR 混合渲染。</p><p>📒 <a href="https://mp.weixin.qq.com/s/KwmNzTdjMB-ljQ0ysEGalg" target="_blank" rel="noopener noreferrer">深入理解 Linux CPU 上下文切换</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/qUiiUkKOyW-QnBz1WEOTwQ" target="_blank" rel="noopener noreferrer">中后台 CSS Modules 最佳实践</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/5UHSGnnAr1-j37AgJ6t0eQ" target="_blank" rel="noopener noreferrer">在 React 中实现条件渲染的 7 种方法</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/PhuFfNAhvXAqW4eSbUqpKQ" target="_blank" rel="noopener noreferrer">2022年值得使用的 Node.js 框架</a></p><p>📒 解决 Vite 无法全局启用 css module 的问题</p><p>在这里打个断点看看：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">packages/vite/src/node/plugins/css.ts:688</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  modules</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> modulesOptions</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  preprocessorOptions</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  devSourcemap</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">css </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> isModule </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> modulesOptions </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> cssModuleRE</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">test</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <code>useRef</code> 在列表渲染场景需要特别注意</p><p>在列表渲染的时候，不能对列表的每一项使用 <code>ref</code>，否则会出现 bug。这种情况下，应该将列表的每一项封装为组件，在组件内部使用 <code>ref</code>：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">IProps</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  questionList</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FC</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">IProps</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> questionList </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> ref </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">questionList</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">          </span><span class="token tag attr-name" style="color:#00a4db">classNames</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">list-item</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">          </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">index</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">          </span><span class="token tag attr-name" style="color:#00a4db">ref</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">ref</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">        </span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">          </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 100 行代码实现 React 路由</p><blockquote><p><a href="https://github.com/ashok-khanna/react-snippets/blob/main/Router.js" target="_blank" rel="noopener noreferrer">https://github.com/ashok-khanna/react-snippets/blob/main/Router.js</a></p></blockquote><blockquote><p><a href="https://juejin.cn/post/7100736564979826695" target="_blank" rel="noopener noreferrer">精读《react-snippets - Router 源码》</a></p></blockquote><p>📒 如何实现多行文本省略</p><p>这个功能不需要自己实现，自己实现还可能存在兼容性问题。只需要使用 antd 的 <code>Typography</code> 组件就可以了：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports operator" style="color:#393A34">*</span><span class="token imports"> </span><span class="token imports keyword module" style="color:#00009f">as</span><span class="token imports"> </span><span class="token imports maybe-class-name">React</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">Typography</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"antd"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token maybe-class-name">Paragraph</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">Typography</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FC</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Paragraph</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">      </span><span class="token tag attr-name" style="color:#00a4db">ellipsis</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f"> rows</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript number" style="color:#36acaa">2</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"> expandable</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript boolean" style="color:#36acaa">true</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript builtin" style="color:#00009f">symbol</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript string" style="color:#e3116c">'more'</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">    </span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Paragraph</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/7100747501338099749" target="_blank" rel="noopener noreferrer">HTTP 的缓存为什么这么设计</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/4MmBSD-d-9T5-kFhcWNlTA" target="_blank" rel="noopener noreferrer">vscode插件原理浅析与实战</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[5月22日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月22日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月22日内容汇总"/>
        <updated>2022-05-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 PNPM 源码结构 - 前端包管理工具具有哪些功能]]></summary>
        <content type="html"><![CDATA[<p>📒 PNPM 源码结构 - 前端包管理工具具有哪些功能</p><p>首先 pnpm 整个项目的主入口包文件为 <code>packages/pnpm</code> 这个包里面，这个包名称也直接叫做 <code>pnpm </code>，其中 <code>main.ts</code> 文件是其入口文件，这个文件会处理掉用户传进来的一些参数，然后根据处理后的不同的参数对各命令做一个下发执行工作，下发后的命令参数再到各个包里面去，从而执行里面对应的逻辑。</p><p>处理参数用到的包为 <code>@pnpm/parse-cli-args</code> ，它会接收到用户传递进来的命令行参数，然后将其处理成一个 pnpm 内部的统一格式，例如用户输入如下命令:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">pnpm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> -D axios</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这里传进来的一些参数都会被 <code>parseCliArgs</code> 这个方法处理:</p><p>例如 <code>add</code> 会被处理给 <code>cmd</code> 字段，一些裸的参数例如 <code>axios</code> 会被放进 <code>cliParams</code> 这个数组中，<code>-D</code> 这个参数在 <code>cliOptions</code> 里面去。处理后的这些变量以及参数用于主入口文件后续代码执行逻辑的判断。具体的判断逻辑可以在调试的时候遇到了，再去看对应的入口逻辑判断调试即可，这里不做具体的介绍。</p><p>在 <code>main.ts</code> 中会通过调用当前包下面的 <code>cmd</code> 目录下面的方法(<code>pnpmCmds</code>)，来完成各命令的分发。</p><ul><li>依赖管理：如果 cmd 值为 <code>add</code> 、<code>install</code> 、<code>update</code> 等这些涉及和依赖安装相关的包，则会走 <code>@pnpm/plugin-commands-installation</code> 这个包里面对应的子命令逻辑(基本上 pnpm 所有的核心模块都围绕依赖安装这一块展开)</li><li>打包发布：如果 cmd 值为 <code>pack</code> 、<code>publish</code> 这一类涉及到打包发布的包，则会走 <code>@pnpm/plugin-commands-publishing</code> 这个包的逻辑</li><li>命令执行：如果 cmd 值为 <code>run</code> 、<code>exec</code> 、 <code>dlx</code> 等这些和命令执行相关的方法，则会走 <code>@pnpm/plugin-commands-script-runners</code> 这个包的逻辑</li></ul><p>📒 学习 swr 获取数据的思路</p><p>最近遇到很多列表渲染的场景，例如根据筛选项和分页参数获取列表数据。在代码中看到虽然用了 React Hooks，但是获取数据依旧是 jQuery 时代的 <strong>命令式</strong> 写法。</p><p>我们知道，前端框架都是数据驱动、声明式渲染的，即渲染视图不需要命令式地操作 DOM，而是声明式地修改数据就行。因此，获取数据也可以使用 <strong>声明式</strong> 写法，这样代码更容易维护。</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">useSWR</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'swr'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Profile</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> error </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useSWR</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/api/user'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fetcher</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">failed to load</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">loading...</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">hello </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text">!</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://swr.vercel.app/docs/getting-started" target="_blank" rel="noopener noreferrer">https://swr.vercel.app/docs/getting-started</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/ovwjufnPmCoYNLMkv5xv2g" target="_blank" rel="noopener noreferrer">【第2618期】手把手教你定制一套适合团队的微前端体系</a></p><p>📒 Vite 相关 issue 梳理</p><p><a href="https://github.com/vitejs/vite/discussions/8232" target="_blank" rel="noopener noreferrer">https://github.com/vitejs/vite/discussions/8232</a></p><p>📒 Chrome debugger 小技巧</p><p>在 Chrome 浏览器中打断点调试，此时切到控制台，可以访问断点位置上下文信息，也就是说可以访问、甚至修改变量。</p><p>⭐️ <a href="https://juejin.cn/post/7099402445989609479" target="_blank" rel="noopener noreferrer">前端必学的动画实现思路，高逼格的效果老板看了都会大声称赞</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/LSlgpazCwtceQWjHsMPCAg" target="_blank" rel="noopener noreferrer">【第2617期】React 组件库 CSS 样式方案分析</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/X4ni2i9bvolHGfCdf3SzIA" target="_blank" rel="noopener noreferrer">【第2616期】解释JavaScript的内存管理</a></p><p>📒 UMI3源码解析系列之插件化架构核心</p><p>插件机制实现的方式：</p><ul><li>umi：基于 tapable 的发布订阅模式，在路由、生成文件、构建打包、HTML 操作、命令等方面提供能力</li><li>babel：基于 visitor 的访问者模式，对于 AST 的操作等</li><li>rollup：基于 hook 的回调模式，定制构建和打包阶段的能力</li><li>webpack：基于 tapable 的发布订阅模式，loader 不能实现的都靠它</li><li>vue-cli：基于 hook 的回调模式，在生成项目、项目运行和 vue ui 阶段提供能力</li></ul><p><a href="https://mp.weixin.qq.com/s/y-6Uf1hNBF19MabHEtqnJA" target="_blank" rel="noopener noreferrer">UMI3源码解析系列之插件化架构核心</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/OVCWcqpMw09T7ml-mn-OcA" target="_blank" rel="noopener noreferrer">写了一个基于 MacOS + iTerm2 自动执行化执行工具</a></p><p>📒 介绍全新的 JSX 转换</p><p>由于浏览器无法识别 JSX 语法，所以我们需要通过 Babel、TypeScript 等工具将 JSX 编译为浏览器能识别的 render 函数。在 React 17 之前，JSX 会转换为 <code>React.createElement(...)</code> 调用：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">App</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'h1'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Hello world'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>正是因为 JSX 会转换为 <code>React.createElement(...)</code>，所以每个组件顶部必须导入 <code>React</code></p></blockquote><p>在 React 17 版本，React 的 package 中引入了两个新入口，这些入口只会被 Babel 和 TypeScript 等编译器使用。新的 JSX 转换不会将 JSX 转换为 React.createElement，而是自动从 React 的 package 中引入新的入口函数并调用。下方是新 JSX 被转换编译后的结果：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 由编译器引入（禁止自己引入！）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> jsx </span><span class="token imports keyword module" style="color:#00009f">as</span><span class="token imports"> _jsx </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react/jsx-runtime'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">App</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">_jsx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'h1'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">children</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Hello world'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>注意，此时源代码无需引入 React 即可使用 JSX 了！（但是如果使用 React 提供的 Hook 或其他导出，这种情况下仍需引入 React）</p></blockquote><p>新的 JSX 转换对应的配置是 <code>runtime: "automatic"</code>：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// babel.config.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">presets</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">"@babel/preset-react"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 新的 JSX 转换 -&gt; automatic</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 旧的 JSX 转换 -&gt; classic</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">runtime</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"automatic"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>可以直接在 Babel Playground 看编译结果：</p><p><a href="https://babeljs.io/repl" target="_blank" rel="noopener noreferrer">https://babeljs.io/repl</a></p><p>官方文档表示，新的 JSX 转换会略微优化包体积，个人认为优化还是比较有限。虽说 <code>React.createElement()</code> 变成了更短的调用，但是又多出来一段运行时代码。</p><p><a href="https://react.docschina.org/blog/2020/09/22/introducing-the-new-jsx-transform.html" target="_blank" rel="noopener noreferrer">https://react.docschina.org/blog/2020/09/22/introducing-the-new-jsx-transform.html</a></p></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/OrekHmMrn8UlisTrvt3MNA" target="_blank" rel="noopener noreferrer">从 Turborepo 看 Monorepo 工具的任务编排能力</a></p><p>📒 大牛书单 | 学习 Golang 资料</p><ul><li>Golang 入门：<a href="https://go.dev/learn/" target="_blank" rel="noopener noreferrer">https://go.dev/learn/</a></li><li>Golang 进阶：<a href="https://github.com/golang/go/wiki#learning-more-about-go" target="_blank" rel="noopener noreferrer">https://github.com/golang/go/wiki#learning-more-about-go</a></li></ul><p>📒 <a href="https://mp.weixin.qq.com/s/GryL1QVARtMB8-WIzd7xQQ" target="_blank" rel="noopener noreferrer">解决前端常见问题：竞态条件</a></p><p>📒 React Router v6 新手指南</p><blockquote><p><a href="https://www.youtube.com/watch?v=59IXY5IDrBA" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=59IXY5IDrBA</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/jCNcAD8y3IElZN6OPv1Qfw" target="_blank" rel="noopener noreferrer">[<!-- -->调研报告<!-- -->]<!-- --> 新一代前端构建工具汇总</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3v54arsDRRw6agyr3MtPRg" target="_blank" rel="noopener noreferrer">Google 最新的性能优化方案，LCP 提升30%！</a></p><p>📒 React useEvent：砖家说的没问题</p><p>useEvent 会将一个函数「持久化」，同时可以保证函数内部的变量引用永远是最新的。如果你用过 ahooks 的 <code>useMemoizedFn</code>，实现的效果是几乎一致的。再强调下 <code>useEvent</code> 的两个特性：</p><ul><li>函数地址永远是不变的</li><li>函数内引用的变量永远是最新的</li></ul><p>通过 <code>useEvent</code> 代替 <code>useCallback</code> 后，不用写 <code>deps</code> 函数了，并且函数地址永远是固定的，内部的 state 变量也永远是最新的。</p><p>useEvent 的实现原理比较简单：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useEvent</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">handler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> handlerRef </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 用于确保函数内引用的变量永远是最新的</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">useLayoutEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    handlerRef</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> handler</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 用于确保返回的函数地址永远不变</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useCallback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter spread operator" style="color:#393A34">...</span><span class="token parameter">args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> fn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> handlerRef</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://mp.weixin.qq.com/s/-6bQKIjH6WPcfuiCFtsjng" target="_blank" rel="noopener noreferrer">React useEvent：砖家说的没问题</a></p><p>📒 为什么用 Vite 打包 React 组件库</p><ul><li>生产环境 rollup 打包 + 开发环境 devServer</li><li>开发环境可以通过 <code>@vitejs/plugin-react</code> 插件支持 fast-refresh</li><li>生产环境默认使用 esbuild 代码压缩，效率是 terser 的 20-40 倍</li><li>esbuild 在语法转换这块尚不完善，但是组件库打包不用考虑兼容性问题，兼容性问题交给业务项目解决</li><li>Vite 提供了很多 esbuild 尚不支持的特性（例如 CSS 模块化等）</li><li>开发环境和生产环境几乎可以复用一套配置（Vite 抹平了 esbulid 和 rollup 配置差异）</li></ul>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[5月15日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月15日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月15日内容汇总"/>
        <updated>2022-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 解决 Vite 打包 React 组件库无法排除 peerDependencies 的问题]]></summary>
        <content type="html"><![CDATA[<p>📒 解决 Vite 打包 React 组件库无法排除 peerDependencies 的问题</p><p><a href="https://zhuanlan.zhihu.com/p/354572830" target="_blank" rel="noopener noreferrer">轮子系列：使用vite从零开发React组件库</a></p><p><a href="https://zhuanlan.zhihu.com/p/500883016" target="_blank" rel="noopener noreferrer">如何使用Rollup打包React组件库</a></p><p>使用 dumi 实现组件库文档自动化</p><p><a href="https://d.umijs.org/zh-CN/guide/advanced#%E7%BB%84%E4%BB%B6-api-%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90" target="_blank" rel="noopener noreferrer">https://d.umijs.org/zh-CN/guide/advanced#%E7%BB%84%E4%BB%B6-api-%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90</a></p><p>📒 <a href="https://juejin.cn/post/7095354780079357966" target="_blank" rel="noopener noreferrer">NodeJs进阶开发、性能优化指南</a></p><p>📒 使用 <code>URLSearchParams</code> 注意事项</p><p>很多同学都会用 <code>URLSearchParams</code> 解析、拼接 query 参数，非常方便，而且还能自动进行参数编码、解码。但是在使用的时候，有几个注意事项：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> p </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">URLSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 1. 当某个 value 为 undefined 时，会直接转为字符串拼接到 URL 上</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dby"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword nil" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2333</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 'dby=undefined&amp;dm=2333'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 解决方案，使用逻辑或操作</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dby"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword nil" style="color:#00009f">undefined</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 'dby=&amp;dm=2333'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2. get 一个不存在的值，返回的是 null，因此 TS 会推导为联合类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"foo"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// string | null</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 解决方案，使用逻辑或操作，实现类型守卫</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"foo"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// string</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/6938201650012094495" target="_blank" rel="noopener noreferrer">写给前端的手动内存管理基础入门（一）返璞归真：从引用类型到裸指针</a></p><p>📒 <a href="https://juejin.cn/post/7097406514360483877" target="_blank" rel="noopener noreferrer">React如何原生实现防抖</a></p><p>📒 <a href="https://juejin.cn/post/7096070620105932813" target="_blank" rel="noopener noreferrer">你想知道vite核心原理吗，我来手写告诉你（80行源代码）</a></p><p>📒 <a href="https://juejin.cn/post/7094909263847358472" target="_blank" rel="noopener noreferrer">Rust 入门 - 资源与生命周期</a></p><p>📒 <a href="https://dev.to/wiseai/the-ultimate-guide-to-software-engineering-545e" target="_blank" rel="noopener noreferrer">The Ultimate Guide To Software Engineering</a></p><p>📒 Tree shaking问题排查指南来啦</p><p>Tree shaking在不同工具里的意义不太统一，为了统一后续讨论，我们规范各个术语：</p><ul><li>minify：编译优化手段，指在不影响代码语义的情况下，尽可能的减小程序的体积，常见的 minify 工具如 terser、uglify，swc 和 esbuid 也自带 minify 功能</li><li>Dead code elimination(DCE)：即死代码优化，一种编译器优化手段，用于移除不影响程序结果的代码，实现DCE的手段有很多种，如 const folding (常量折叠)、Control flow analysis、也包括下面的 LTO</li><li>Link Time Optimization：指 link 期优化的手段，可以进行跨模块的分析优化，如可以分析模块之间的引用关系，删掉其他模块未使用的导出变量，也可以进行跨模块对符号进行 mangle <a href="http://johanengelen.github.io/ldc/2016/11/10/Link-Time-Optimization-LDC.html" target="_blank" rel="noopener noreferrer">http://johanengelen.github.io/ldc/2016/11/10/Link-Time-Optimization-LDC.html</a></li><li>Tree shaking：一种在 Javascript 社区流行的一个术语，是一种死代码优化手段，其依赖于 ES2015 的模块语法，由 rollup 引入。这里的 tree shaking 通常指的是基于 module 的跨模块死代码删除技术，即基于 LTO 的 DCE，其区别于一般的 DCE 在于，其只进行 top-level 和跨模块引用分析，并不会去尝试优化如函数里的实现的 DCE</li></ul><blockquote><p>Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. It relies on the static structure of ES2015 module syntax, i.e. import and export. The name and concept have been popularized by the ES2015 module bundler rollup.   </p><p><a href="https://webpack.js.org/guides/tree-shaking/" target="_blank" rel="noopener noreferrer">https://webpack.js.org/guides/tree-shaking/</a></p></blockquote><ul><li>mangle：即符号压缩，将变量名以更短的变量名进行替换</li><li>副作用：对程序状态造成影响，死代码优化一般不能删除副作用代码，即使副作用代码的结果在其他地方没用到</li><li>模块内部副作用：副作用影响范围仅限于当前模块，如果外部模块不依赖当前模块，那么该副作用代码可以跟随当前模块一起被删除，如果外部模块依赖了当前模块，则该副作用代码不能被删除</li></ul><p><img loading="lazy" alt="image" src="/assets/images/tree_shaking-19829ee33097b669151380439207d188.png" width="654" height="573" class="img_ev3q"></p><p>因此我们的后续讨论，所说的 tree shaking 均是指基于 LTO 的 DCE，而 DCE 指的是不包含 tree shaking 的其他 DCE 部分。</p><blockquote><p>简单来说即是，tree shaking 负责移除未引用的 top-level 语句，而 DCE 删除无用的语句</p></blockquote><p><a href="https://mp.weixin.qq.com/s/P3mzw_vmOR6K_Mj-963o3g" target="_blank" rel="noopener noreferrer">Tree shaking问题排查指南来啦</a></p><p>📒 <!-- -->[<!-- -->科普<!-- -->]<!-- --> JS中Object的keys是无序的吗</p><p><strong>1. <code>Object.keys()</code> 返回类型始终为 <code>string[]</code></strong></p><p>因为 JS 对象 key 的类型只有三种：<code>number</code>、<code>string</code>、<code>Symbol</code>，需要注意 <code>number</code> 类型底层也是按 <code>string</code> 进行存储，而 <code>Symbol</code> 类型不可枚举。</p><p><strong>2. ES2015 之后 <code>Object.keys()</code> 输出顺序是可以预测的</strong></p><p>我们说普通对象的 Key 是无序的，不可靠的，指的是不能正确维护插入顺序，与之相对的是 Map 实例会维护键值对的插入顺序。</p><p>在 ES2015 之后，普通对象 Key 顺序是可预测的。先按照自然数升序进行排序，然后按照非数字的 String 的加入时间排序，然后按照 Symbol 的时间顺序进行排序。也就是说他们会先按照上述的分类进行拆分，先按照自然数、非自然数、Symbol 的顺序进行排序，然后根据上述三种类型下内部的顺序进行排序。</p><blockquote><p>使用 <code>Object.keys()</code> 只会输出对象自身可枚举属性的 key，不含 <code>Symbol</code> 类型的 key。如果要输出 <code>Symbol</code> 类型 key，可以使用 <code>Reflect.ownKeys()</code></p></blockquote><p><a href="https://mp.weixin.qq.com/s/qyyrQNC6q6p496OdZIQ6ew" target="_blank" rel="noopener noreferrer">[<!-- -->科普<!-- -->]<!-- --> JS中Object的keys是无序的吗</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/FPupefVg4zphOfIERZOvHQ" target="_blank" rel="noopener noreferrer">如何设计更优雅的 React 组件</a></p><p>📒 代码覆盖率在性能优化上的一种可行应用</p><p>由于 JS 资源需要通过网络加载，代码的体积直接影响页面加载性能。很多时候我们“喂”给浏览器的代码，并不会全部执行，因此我们可以做分包优化，即 code-spliting，只“喂”给浏览器渲染当前页面所需的资源。</p><p>注意区分以下两个概念：</p><ul><li><p>Dead code</p><p>也叫无用代码，这个概念应是在编译时静态分析出的对执行无影响的代码。通常我们用 Tree Shaking 在编译时移除这些 dead code 以减小代码体积。</p></li><li><p>冗余代码</p><p>代码覆盖率中的概念，适用于运行时，而 Dead code 适用于编译时。Dead code 是任何情况下都不会执行的代码，所以可以在编译阶段将其剔除。冗余代码是某些特定的业务逻辑之下并不会执行到这些代码逻辑（比如：在首屏加载时，某个前端组件完全不会加载，那么对于“首屏”这个业务逻辑用例来讲，该前端代码就是冗余的）。</p></li></ul><p>如何进行合理分包呢？这就需要统计代码覆盖率。代码覆盖率（Code coverage）是软件测试中的一种度量指标。即描述测试过程中（运行时）被执行的源代码占全部源代码的比例。</p><p>如何统计代码覆盖率：</p><p><strong>1. Chrome 浏览器 Dev Tools</strong></p><p>chrome 浏览器的 DevTools 给我们提供了度量页面代码（JS、CSS）覆盖率的工具 Coverage。使用方式：Dev tools —— More tools —— Coverage</p><p>由于一般都会对 JS、CSS 资源进行混淆压缩，因此建议导入 Source Map 以便查看源代码的覆盖率。</p><p><strong>2. Istanbul（NYC）</strong></p><p>Istanbul或者 NYC(New York City，基于 istanbul 实现) 是度量 JavaScript 程序的代码覆盖率工具，目前绝大多数的node代码测试框架使用该工具来获得测试报告，其有四个测量维度：</p><ul><li>line coverage（行覆盖率）：每一行是否都执行了 【一般我们关注这个信息】</li><li>function coverage（函数覆盖率）：每个函数是否都调用了</li><li>branch coverage（分支覆盖率）：是否每个 if 代码块都执行了</li><li>statement coverage（语句覆盖率）：是否每个语句都执行了</li></ul><p>缺点：目前使用 istanbul 度量网页前端JS代码覆盖率没有非侵入的方案，采用的是在编译构建时修改构建结果的方式埋入统计代码，再在运行时进行统计展示。</p><p>我们可以使用 babel-plugin-istanbul 插件在对源代码在 AST 级别进行包装重写，这种编译方式也叫 代码插桩 / 插桩构建（instrument）。</p><p><a href="https://mp.weixin.qq.com/s/VQq3Ly3ZEAFpYVIvV3Uhiw" target="_blank" rel="noopener noreferrer">代码覆盖率在性能优化上的一种可行应用</a></p><p>📒 关于“环境变量”需要注意的问题</p><p><strong>1. 为什么使用 cross-env 设置环境变量</strong></p><p>有时候我们需要用 npm scripts 设置 Node.js 的环境变量，通常都会使用 cross-env 这个库。其实设置环境变量，在 MacOS 和 linux 系统直接通过 shell 命令就可以了，例如 <code>PORT=8066</code>，但是 Win 设置的方式不太一样，所以 cross-env 实际上是实现了跨平台设置环境变量。</p><p><strong>2. <code>.env</code> 文件是如何生效的</strong></p><p>可以使用 <code>dotenv</code> 这个库，可以将 <code>.env</code> 文件下的内容加载到 Node.js 的 <code>process.env</code> 对象中，注意 key 和 value 都是 string 类型。</p><p><strong>3. 前端项目的环境变量是如何生效的</strong></p><p>前端项目的环境变量，实际上不是真正的环境变量，因为浏览器环境下是访问不到 <code>process</code> 对象的，需要通过 <code>DefinePlugin</code> 在打包构建的时候，将变量替换为对应的值。</p><p>注意这里有个坑，<code>DefinePlugin</code> 默认直接进行文本替换，如果想要替换为字符串字面量，则需要在字符串中再加一个引号，或者用 <code>JSON.stringify</code> 包裹：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// webpack.config.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">webpack</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">DefinePlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">__DEV__</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"true"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 替换为布尔值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string-property property" style="color:#36acaa">"process.env.NODE_ENV"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">stringify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"development"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 替换为字符串字面量</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 源码</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__DEV__</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NODE_ENV</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"development"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 替换得到的结果</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"development"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"development"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>使用 DefinePlugin 遇到的问题</p><p>在开发一个组件库，需要区分运行环境，根据环境打包相应的模块代码。根据 Webpack 代码优化（生产环境默认启用）的时候，terser 会做 DCE（无用代码移除）处理，进而优化打包体积：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 在 Webpack 代码优化的时候</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// terser 会识别出“业务2”的代码为无用代码，进而移除掉</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 只保留“业务1”的代码</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 业务 1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 业务 2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>原先的方式在一个模块中定义常量，然后其他模块引入常量进行判断。这里要注意一个问题，在 Webpack 代码优化的时候，terser 并不会做程序流分析，也就是说访问不到模块的上下文信息。这种情况下，terser 可能还是会将模块导出的常量当做变量处理，从而导致 DCE 失效。这种情况下，我们不能通过模块方式引入常量，而是要用 <code>DefinePlugin</code> 直接把变量替换为对应的字面量。</p><p>📒 <a href="https://mp.weixin.qq.com/s/y0QGSI-VZcy9CCe_cHezlw" target="_blank" rel="noopener noreferrer">治理项目模块依赖关系，试试这艘「依赖巡洋舰」</a></p><p>📒 【前端部署十二篇】使用 CI 中的缓存进行 Pipeline 优化</p><p>当我们使用 webpack 5 进行构建时，如果使用了 <code>filesystem cache</code>，因为在磁盘中含有缓存 (node_modules/.cache)，二次构建往往比一次构建快速十几倍。</p><p>而在 CICD 中，这些都失去了意义，因为 CICD 每次 Job 都相当于新建了一个目录，「每次构建都相当于是首次构建」。</p><p>但是，CI 提供了一些缓存机制，可以将一些资源进行缓存。如果每次可以将缓存取出来，则大大加速了前端部署的速度。</p><p><a href="https://mp.weixin.qq.com/s/7300HTz9nOOuCq_xTwXHhg" target="_blank" rel="noopener noreferrer">【前端部署十二篇】使用 CI 中的缓存进行 Pipeline 优化</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/f8mYoozpLrnSfWcRHTMa7A" target="_blank" rel="noopener noreferrer">UMI3源码解析系列之核心service类初始化</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fPcdVCqWvkPqAdVK7JHacg" target="_blank" rel="noopener noreferrer">【第2610期】JavaScript Containers</a></p><p>📒 【前端部署十一篇】通过 CICD 实践 Lint、Test、Performance 等前端质量保障工程</p><p>在 CI 操作保障代码质量的环节中，可确定以下时机:</p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 1. 当功能分支代码 push 到远程仓库后，进行 CI</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">push</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">branches</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'feature/**'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 2. 当功能分支代码 push 到远程仓库以及是 Pull Request 后，进行 CI</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">pull_request</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">types</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic"># 当新建了一个 PR 时</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> opened</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic"># 当提交 PR 的分支，未合并前并拥有新的 Commit 时</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> synchronize</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">branches</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'feature/**'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>CRA 内部使用 <code>ESLint Plugin</code> 进行代码检查，而非命令的方式。当 ESLint 存在问题时，CRA 如果判断当前是 CI 环境，则直接报错并退出进程，导致打包失败：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ESLintPlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Plugin options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">failOnError</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">isEnvDevelopment </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> emitErrorsAsWarnings</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Lint 和 Test 仅是 CI 中最常见的阶段。为了保障我们的前端代码质量，还可以添加以下阶段：</p><ul><li>Audit: 使用 npm audit 或者 snyk 检查依赖的安全风险</li><li>Quality: 使用 SonarQube 检查代码质量</li><li>Container Image: 使用 trivy 扫描容器镜像安全风险</li><li>End to End: 使用 Playwright 进行 UI 自动化测试</li><li>Bundle Chunk Size Limit: 使用 size-limit 限制打包体积，打包体积过大则无法通过合并</li><li>Performance (Lighthouse CI): 使用 lighthouse CI 为每次 PR 通过 Lighthouse 打分，如打分过低则无法通过合并</li></ul><p>有些细心并知识面广泛的同学可能注意到了，某些 CI 工作也可在 Git Hooks 完成，确实如此。</p><p>它们的最大的区别在于一个是客户端检查，一个是服务端检查。而客户端检查是天生不可信任的。</p><p>而针对 <code>git hooks</code> 而言，很容易通过 <code>git commit --no-verify</code> 而跳过。</p><p><a href="https://mp.weixin.qq.com/s/D7nXxYUMdMuo1du6fHnT-g" target="_blank" rel="noopener noreferrer">【前端部署十一篇】通过 CICD 实践 Lint、Test、Performance 等前端质量保障工程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/fhSMz8BEIyjFGVnJtcVrKg" target="_blank" rel="noopener noreferrer">【第2609期】Javascript之迪米特法则</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/01sTK6w4BFUzoRc2NKCs1w" target="_blank" rel="noopener noreferrer">React 并发渲染的前世今生</a></p><p>📒 如何优雅实现轮询</p><ul><li>初级：使用定时器（<code>setInterval</code>）</li><li>中级：使用基于事件循环的递归（<code>setTimeout</code> 递归调用）</li><li>高级：使用轮询调度器</li></ul><p>📒 npm 包的入口点</p><p>注意 <code>exports</code> 字段优先级最高，当提供 <code>exports</code> 字段后，<code>main</code>、<code>module</code> 字段会被覆盖。</p><p><code>exports</code> 可以更容易地控制子目录的访问路径，不在 <code>exports</code> 字段中的模块，即使直接访问路径，也无法引用！</p><p><a href="https://juejin.cn/post/7025809061660590087" target="_blank" rel="noopener noreferrer">工程化知识卡片 014: 发包篇之 package.json 中 main、export、module 的区别何在</a></p><p><a href="http://nodejs.cn/api/packages.html#main-entry-point-export" target="_blank" rel="noopener noreferrer">http://nodejs.cn/api/packages.html#main-entry-point-export</a></p><p>📒 使用 Next.js 和 MDX 构建你自己的博客</p><blockquote><p><a href="https://www.freecodecamp.org/news/how-to-build-your-own-blog-with-next-js-and-mdx/" target="_blank" rel="noopener noreferrer">https://www.freecodecamp.org/news/how-to-build-your-own-blog-with-next-js-and-mdx/</a></p></blockquote><p>📒 React Concurrent 的故事</p><blockquote><p><a href="https://www.youtube.com/watch?v=NZoRlVi3MjQ" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=NZoRlVi3MjQ</a></p></blockquote><p>⭐️ <a href="https://mp.weixin.qq.com/s/toQUgqJHeUbFZMtxfzFCxw" target="_blank" rel="noopener noreferrer">TCP 重传、滑动窗口、流量控制、拥塞控好难？看完图解就不愁了</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/9kHoRk6QIYOFUR_PCmHY6g" target="_blank" rel="noopener noreferrer">TCP 就没什么缺陷吗？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/b9Ye4iShgTSAcm0ce6m_9Q" target="_blank" rel="noopener noreferrer">React Server Components：我们即将和 API 告别？</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[5月8日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月8日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月8日内容汇总"/>
        <updated>2022-05-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 从零开始构建 JavaScript Bundler]]></summary>
        <content type="html"><![CDATA[<p>📒 从零开始构建 JavaScript Bundler</p><p>Jest 作者的最新系列文章，并且配套视频，内容绝对硬核。</p><blockquote><p><a href="https://cpojer.net/posts/building-a-javascript-bundler" target="_blank" rel="noopener noreferrer">https://cpojer.net/posts/building-a-javascript-bundler</a></p></blockquote><p>📒 JavaScript 框架的四个时代</p><p>这篇文章作者以自身多年的开发经历还原了 JavaScript 框架的发展历程，并划分出了四个时代。</p><ul><li>远古时代：无框架</li><li>框架初期：Backbone.js、Angular 1、Knockout.js、SproutCore、Ember.js、Meteor.js</li><li>以组件为中心的时代：React.js、Vue.js、Svelte、Polymer.js</li><li>全栈框架：Next.js、Nuxt.js、Remix、SvelteKit、Gastby 和 Astro</li></ul><blockquote><p><a href="https://www.pzuraq.com/blog/four-eras-of-javascript-frameworks" target="_blank" rel="noopener noreferrer">https://www.pzuraq.com/blog/four-eras-of-javascript-frameworks</a></p></blockquote><p>📒 pnpm v7.0.0</p><p>pnpm 发布了 v7.0.0，带来了大量的更新。如：不再支持 Node.js 12、<code>pnpm run &lt;script&gt;</code> 脚本名称后的所有命令行参数都会传递给 argv 等等。</p><blockquote><p><a href="https://github.com/pnpm/pnpm/releases/tag/v7.0.0" target="_blank" rel="noopener noreferrer">https://github.com/pnpm/pnpm/releases/tag/v7.0.0</a></p></blockquote><p>⭐️ 2022 年的前端行业，咋样啦</p><p>ESR（Edge Side Rendering，边缘渲染）是最近的一大热门趋势，可以直接在 CDN 级别实现按需渲染。Nuxt 3、Remix 以及 Sveltekit 等框架都在朝着这个方向发展，目测会在未来的一到两年会成为一大焦点。</p><p><a href="https://mp.weixin.qq.com/s/SLi0MQru1bh539ricvQCew" target="_blank" rel="noopener noreferrer">2022 年的前端行业，咋样啦</a></p><p>📒 <a href="https://github.com/nodejs/docker-node#create-a-dockerfile-in-your-nodejs-app-project" target="_blank" rel="noopener noreferrer">docker-node - Node.js 官方 Docker 镜像</a></p><p>📒 JS 新的日期 API：Temporal</p><p>这项特性提案时间为 2021 年 7 月，不到一年的时间已经进展到 stage-3 阶段，目前组委会已经在在做它的功能实现，有望在下个版本推出。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>该项提案的初衷来自这篇文章，因为 JavaScript 最初关于日期的实现是照搬的 Java 方案，但由于各种限制和问题，Java 早在 1997 年就实现 Calendar 做了功能改进，而 JavaScript 时至今日用的还是老旧方案，改进优化实在是迫在眉睫。</p><p><a href="https://maggiepint.com/2017/04/09/fixing-javascript-date-getting-started/" target="_blank" rel="noopener noreferrer">https://maggiepint.com/2017/04/09/fixing-javascript-date-getting-started/</a></p></div></div><p>官方文档（打开控制台就可以体验 Polyfill）：</p><blockquote><p><a href="https://tc39.es/proposal-temporal/docs/" target="_blank" rel="noopener noreferrer">https://tc39.es/proposal-temporal/docs/</a></p></blockquote><p>或者在 RunKit 上体验（浏览器端运行 node 模块）：</p><blockquote><p><a href="https://npm.runkit.com/proposal-temporal" target="_blank" rel="noopener noreferrer">https://npm.runkit.com/proposal-temporal</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/zt7x2KjMT_cWvLVVa2-Hww" target="_blank" rel="noopener noreferrer">【工程化】探索webpack5中的Module Federation</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/xd6hjcxCm5dpRF95QawmxA" target="_blank" rel="noopener noreferrer">我们如何使用 Webpack 将启动时间减少 80%</a></p><p>📒 <a href="https://juejin.cn/post/7094424941541457933" target="_blank" rel="noopener noreferrer">React官方团队出手，补齐原生Hook短板</a></p><p>📒 <a href="https://juejin.cn/post/7094296981001994277" target="_blank" rel="noopener noreferrer">你可能并没有理解的 babel 配置的原理</a></p><p>📒 <a href="https://juejin.cn/post/7083009375387779085" target="_blank" rel="noopener noreferrer">前端抢饭碗系列之Docker进阶部署</a></p><p>📒 <a href="https://juejin.cn/post/7069609959985512484" target="_blank" rel="noopener noreferrer">前端抢饭碗系列之初识Docker容器化部署</a></p><p>📒 <a href="https://juejin.cn/post/7052307032971411463" target="_blank" rel="noopener noreferrer">从零开始发布自己的NPM包</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/-B5M7pjIWZzFNvq-hyr1Mw" target="_blank" rel="noopener noreferrer">Umi 4 特性合集，比 Vite 还要快？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/1QZ37jf_6av1i_ESTPvfaQ" target="_blank" rel="noopener noreferrer">HTTP分块传输 如何在 React18 中应用</a></p><p>📒 <a href="https://www.bilibili.com/video/BV1j44y1g74m" target="_blank" rel="noopener noreferrer">下集」React性能优化，你需要知道的一切</a></p><p>📒 htmlparser2 8.0：快速且高容错的 HTML 和 XML 解析器</p><blockquote><p><a href="https://github.com/fb55/htmlparser2" target="_blank" rel="noopener noreferrer">https://github.com/fb55/htmlparser2</a></p></blockquote><p>📒 Node v18 test 模块</p><p>注意 Node v18 test 模块是第一个 Prefix-Only Core Modules，也就是说加载该模块必须带上 <code>node:</code> 前缀：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">test</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'node:test'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Uses the node: prefix. Loads from core.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">assert</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'assert'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Does not use the node: prefix. Loads from core.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>假如没有带上 <code>node:</code> 前缀，则会尝试从用户空间加载 <code>test</code> 模块。但是对于 Node 其他内置模块来说，加不加 <code>node:</code> 前缀都是一样的。</p><blockquote><p><a href="https://fusebit.io/blog/node-18-prefix-only-modules/" target="_blank" rel="noopener noreferrer">https://fusebit.io/blog/node-18-prefix-only-modules/</a></p></blockquote></div></div><p>📒 Node v16.15.0 (LTS) 发布</p><p>现在 Node v16 可以使用实验性支持的 Fetch API 了</p><blockquote><p><a href="https://nodejs.org/en/blog/release/v16.15.0/" target="_blank" rel="noopener noreferrer">https://nodejs.org/en/blog/release/v16.15.0/</a></p></blockquote><p>📒 升级到 React 18 所对应的 TypeScript 类型定义的改动</p><blockquote><p><a href="https://blog.logrocket.com/upgrading-react-18-typescript/" target="_blank" rel="noopener noreferrer">https://blog.logrocket.com/upgrading-react-18-typescript/</a></p></blockquote><p>📒 如何理解 React Hooks 的闭包陷阱</p><p>函数组件更新，实际上就是函数重新执行，生成一个新的执行上下文，所有变量、函数重新创建，hooks 重新执行。</p><p>一般来说，当函数执行完毕，内部的变量就会销毁、被垃圾回收机制回收。当然也有例外情况，在下面的代码中，函数 <code>baz</code> 依赖了 <code>bar</code> 内部的变量 <code>a</code>，并且 <code>baz</code> 作为返回值传递给了 <code>foo</code>，因此 <code>a</code> 并不会被垃圾回收机制回收，而是会作为闭包缓存下来。只要 <code>foo</code> 的引用不解除，<code>a</code> 就会一直缓存：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">bar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">baz</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">bar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>再来看这个场景：<code>useEffect</code> 的回调函数依赖了 state 变量，而我们知道这个回调函数在下次 rerender 之前都是缓存在 fiber 节点上的，这样一来就创建了闭包，即使函数组件已经执行完毕，但是 state 变量仍会被缓存下来。</p><p>当组件更新的时候，会生成一个新的执行上下文，state 变量也会重新生成，但是 <code>useEffect</code> 回调函数仍然引用了旧的闭包。但是为什么 <code>useEffect</code> 依赖项变化、回调函数执行的时候，总是可以获取到新的值呢？这是因为每次函数组件重新渲染，<code>useEffect</code> 都会重新执行，回调函数也会重新生成（但不一定都会执行），在 <code>updateEffectImpl</code> 内部用重新生成的函数替换了 fiber 节点缓存的函数，这样一来，回调函数执行的时候，始终都能获取到最新的值了。</p><p>你可能会觉得这样没什么问题，但是如果在 <code>useEffect</code> 中使用定时器，大概率都会遇到闭包陷阱。</p><p>另一个会遇到闭包陷阱的是 <code>useCallback</code>。很多同学觉得 <code>useCallback</code> 依赖项似乎没什么用，习惯性传递空数组，这就会导致函数一直被缓存，假如内部依赖了 state 变量，则始终会缓存旧的闭包。正确做法应该是把 state 变量添加到依赖项数组中，在 state 改变的时候重新生成函数，这样就可以获取到最新的值。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>函数组件 rerender 过程中，缓存状态的 fiber 节点（相当于组件实例）并不会销毁，但函数组件是重新执行了，会生成一个新的上下文环境，如果 useEffect 回调依赖了 state 变量，则会一直缓存旧的闭包。所以要避免闭包陷阱，只需要 <strong>保证每次渲染的时候，函数都重新生成</strong> 就行。</p></div></div><p>📒 TypeScript 小技巧：常量断言</p><p>在讲常量断言之前，先提一下，TS 会区别对待可修改和不可修改的值的类型推断：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 推断成单值类型 'dbydm'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> immutable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'dbydm'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 推断成通用的 string 类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> mutable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'dn'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 由于对象的属性都具有可修改性，TS 都会对它们「从宽」类型推断</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 例如下面的 prop 的类型被推断为 string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> obj </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> prop</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'foo'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>再来看下面的代码，例如我们实现了一个用 ref 维护状态的 hook：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> React </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> useRenderlessState </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">initialState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> stateRef </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">initialState</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">setState</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nextState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> stateRef</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nextState</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">stateRef</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">current</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setState</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>此时我们会发现上面 hook 的返回值的类型被推导成了如下的数组类型：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nextState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这就导致我们在使用的时候无法对它进行准确的解构：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setValue</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useRenderlessState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>一般来说我们可以 <strong>显示声明返回类型</strong> 或者 <strong>对返回值做类型断言</strong>，告诉 TS 返回值类型是元组而不是数组：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 显示声明返回类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> useRenderlessState </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">initialState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nextValue</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token comment" style="color:#999988;font-style:italic">/*...*/</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 对返回值对类型断言</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> useRenderlessState </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">initialState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setState</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> setValue</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>上面的两种写法都各有冗余成分，算不上优雅。</p><p>其实从语义层面来分析，TS 之所以没能将返回值推断为元组类型是因为它认为该返回值仍有可能被 push 值，被修改。所以我们真正需要做的是告诉 TS，这个返回值是一个 final，其本身和属性都是不可篡改的，而这正是常量断言所做的事。</p><p>常量断言可以把一个值标记为一个不可篡改的常量，从而让 TS 以最严格的策略来进行类型推断：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> useRenderlessState </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">initialState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setState</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这下 <code>useRenderlessState</code> 的返回类型就被推断成了如下的 readonly 值：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nextState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p><code>as const</code> 与 ES6 <code>const</code> 常量声明的区别：</p><ul><li><code>const</code> 常量声明是 ES6 的语法，对 TS 而言，它只能反映该常量本身是不可被重新赋值的，它的子属性仍然可以被修改，故 TS 只会对它们做松散的类型推断</li><li><code>as const</code> 是 TS 的语法，它告诉 TS 它所断言的值以及该值的所有层级的子属性都是不可篡改的，故对每一级子属性都会做最严格的类型推断（所有的字面量都会被推断为单值类型）</li></ul><p>常量断言可以让我们不需要 <code>enum</code> 关键字就能定义枚举对象：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> EnvEnum </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">DEV</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"development"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">PROD</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"production"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">TEST</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"test"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div><p><a href="https://zhuanlan.zhihu.com/p/121558249" target="_blank" rel="noopener noreferrer">TypeScript 夜点心：常量断言</a></p><p>📒 了解 <code>Symbol.toStringTag</code> 的用法吗</p><p><code>Symbol.toStringTag</code> 是一个内置 symbol，它通常作为对象的属性键使用，对应的值是字符串类型，用来表示该对象的自定义类型标签。通常只有内置的 <code>Object.prototype.toString()</code> 方法会去读取这个标签并把它包含在自己的返回值里。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> bar </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token known-class-name class-name">Symbol</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">toStringTag</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"测试内容"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// '[object Object]'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bar</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// '[object 测试内容]'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag" target="_blank" rel="noopener noreferrer">Symbol.toStringTag - MDN 文档</a></p><p>📒 函数组合中的 <code>compose</code>、<code>flow</code>、<code>pipe</code></p><p><code>compose</code> 实现如下，注意调用顺序是反过来的：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">compose</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter spread operator" style="color:#393A34">...</span><span class="token parameter">fns</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token parameter">x0</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> fns</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">reduceRight</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">x</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">f</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    x0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 接受参数后，返回一个待执行函数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 需要再接受一个初始值才开始执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> processComment </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">compose</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    linkify</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    imagify</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    emphasize</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    headalize</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>flow</code> 实现如下，注意这里调用顺序是从左到右：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">flow</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter spread operator" style="color:#393A34">...</span><span class="token parameter">fns</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token parameter">x0</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> fns</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">x</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">f</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    x0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 注意这里仍然是返回一个待执行函数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> processComment </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">flow</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    headalize</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    emphasize</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    imagify</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    linkify</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    codify</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>pipe</code> 实现如下，调用顺序也是从左到右：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 注意 pipe 直接执行所有的函数，返回一个值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 而 flow 返回一个待执行函数，需要再接受一个初始值才开始执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">pipe</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">x0</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> </span><span class="token parameter spread operator" style="color:#393A34">...</span><span class="token parameter">fns</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> fns</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">x</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">f</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    x0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">map</span><span class="token plain">    </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token parameter">f</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token parameter">arr</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">filter</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token parameter">p</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token parameter">arr</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">take</span><span class="token plain">   </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token parameter">n</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token parameter">arr</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> n</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">join</span><span class="token plain">   </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token parameter">s</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token parameter">arr</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> comments </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">pipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">commentStrs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">noNazi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">take</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">emphasize</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">itemize</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'\n'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://jrsinclair.com/articles/2022/javascript-function-composition-whats-the-big-deal/" target="_blank" rel="noopener noreferrer">什么是 JavaScript 的函数组合</a></p><p>📒 基于依赖倒置原则实现插件机制</p><p>依赖倒置原则（DIP）</p><blockquote><p>核心思想：依赖一个抽象的服务接口，而不是去依赖一个具体的服务执行者，从依赖具体实现转向到依赖抽象接口，倒置过来</p></blockquote><p>例如在 Webpack 中包含一套插件机制：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">WebpackBar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">webpack</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">HotModuleReplacementPlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">MiniCssExtractPlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">filename</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'css/[name].[contenthash:8].css'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">chunkFilename</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'[id].css'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">HtmlWebpackPlugin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">template</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'../public/index.html'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">title</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"React App"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">filename</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"index.html"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Webpack 插件需要实现一个统一的接口，即：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">IPlugin</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">apply</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">compiler</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ICompiler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyPlugin</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">IPlugin</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 构造器可以在初始化的时候接受配置参数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">apply</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">compiler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这样 Webpack 只需要遍历 <code>plugins</code> 数组，顺次调用每个插件上的 <code>apply</code> 方法，传入 <code>compiler</code> 对象即可：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">plugins</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">plugin </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">plugin</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">apply</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">compiler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>顺便提一下，有同学会问，为啥插件要写成 class 的形式，直接用一个对象可以吗，例如：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> MyPlugin </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">apply</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">compiler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>直接用一个对象也是可以的，但是用 class 显然更灵活，可以在初始化的时候接受配置参数</p></blockquote><p>📒 浏览器 JavaScript 和 Node.js 的区别</p><ul><li>API 区别：浏览器 JavaScript 是面向浏览器编程，调用浏览器的 API，例如 <code>document</code>、<code>window</code>。而 Node.js 是面向操作系统编程，没有浏览器 API，相反可以调用 Node 提供的标准库，与操作系统进行交互</li><li>运行环境区别：浏览器 JavaScript 的特殊性（JS 代码需要经过网络请求，在客户端下载并执行），因此无法选择运行环境，需要考虑语法、API 兼容性问题，需要使用 Babel 处理。而 Node.js 通常在本地开发环境、CI 环境、服务端运行，可以控制运行环境，无需考虑兼容性问题</li><li>模块规范区别：浏览器原本没有模块机制，但可以自行实现模块命名空间机制（例如 <code>browserify</code>、<code>webpack</code>），从 Chrome 61 开始支持 <code>&lt;script type="module"&gt;</code>，即浏览器原生支持 <code>import</code> 命令加载模块（需要注意这种方式也是要经过网络请求）。而 Node.js 自带了一套 CommonJS 模块机制，在 Node 14 之后支持 ES Module 规范（注意 CommonJS 仍然是默认启用的模块规范）</li></ul>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[5月1日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月1日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/5月1日内容汇总"/>
        <updated>2022-05-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 实现一个 Code Pen：（三）10 行代码实现代码格式化]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7092283403277434893" target="_blank" rel="noopener noreferrer">实现一个 Code Pen：（三）10 行代码实现代码格式化</a></p><p>📒 为什么用链表实现队列</p><p>很多时候用数组也能实现队列，我们知道数组尾部操作（例如 <code>push</code>、<code>pop</code>）时间复杂度都是 <code>O(1)</code>，但如果在数组头部增删元素（例如 <code>shift</code>、<code>unshift</code>），需要移动其他元素的下标，因此时间复杂度为 <code>O(n)</code>。</p><p>而链表增删元素实际上都是修改指针指向，不需要移动下标，因此时间复杂度都是 <code>O(1)</code>。链表只有查找元素需要遍历，时间复杂度为 <code>O(n)</code>，但是队列并不需要查找，而且链表的 <code>size</code> 属性可以在增删操作的时候进行维护，所以用链表实现队列非常合适。</p><p>思考题：如何在常数时间内删除数组中的元素。我们知道 <code>splice</code> 删除元素也需要移动其他元素下标，时间复杂度为 <code>O(n)</code>，但是在数组尾部操作时间复杂度都是 <code>O(1)</code>，因此可以先把要删除的元素交换到数组尾部，然后直接删除尾部元素即可。</p><p>📒 <a href="https://zhuanlan.zhihu.com/p/445217118" target="_blank" rel="noopener noreferrer">写给前端的 K8S 上手指南</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/wJxj5QbOHwH9cKmqU5eSQw" target="_blank" rel="noopener noreferrer">Web页面全链路性能优化指南</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3PSFMt9cQ1ZCoYQrdOCM6Q" target="_blank" rel="noopener noreferrer">系统困境与软件复杂度，为什么我们的系统会如此复杂</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/MYLi4mSgoi5KXj4-_OgT3A" target="_blank" rel="noopener noreferrer">【第2602期】设置 NPM Registry 的 4 种姿势</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/tWbeOTx0JpiZOD0YaC1P2A" target="_blank" rel="noopener noreferrer">前端算法系统练习: 栈和队列篇</a></p><p>📒 <a href="https://juejin.cn/post/6974262139062059045" target="_blank" rel="noopener noreferrer">怎么解决MySQL死锁问题的</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/OlOMm20cSRaQESiZ_DC7mQ" target="_blank" rel="noopener noreferrer">【第2598期】ServiceWorker 缓存与 HTTP 缓存</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/U00My70CqPtmCE1MbSNdFA" target="_blank" rel="noopener noreferrer">Monorepo 的过去、现在、和未来</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JMl8LOsNYlttxO-KyVK-Vw" target="_blank" rel="noopener noreferrer">【第2597期】如何用JavaScript实现一门编程语言 - AST</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/n6kjr2IFn1fb-_-DFUnD1Q" target="_blank" rel="noopener noreferrer">TS 类型体操：索引类型的映射再映射</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/9VaUq9FOm2_nKNCGaH-7rw" target="_blank" rel="noopener noreferrer">ESBuild &amp; SWC浅谈: 新一代构建工具</a></p><p>📒 InnoDB原理篇：如何用好索引</p><p>我们都知道 InnoDB 索引结构是 B+ 树组织的，但是根据 <strong>数据存储形式不同</strong> 可以分为两类，分别是 <strong>聚簇索引</strong> 与 <strong>二级索引</strong>。</p><p>其实聚簇索引的本质就是主键索引。因为每张表只能拥有一个主键字段，所以每张表只有一个聚簇索引。另外聚簇索引还有一个特点，表的数据和主键是一起存储的，它的叶子节点存放的是整张表的行数据（树的最后一层），叶子节点又称为数据页。</p><blockquote><p>很简单记住一句话：<strong>找到了索引就找到了行数据，那么这个索引就是聚簇索引</strong></p></blockquote><p>知道了聚簇索引，再来看看二级索引是什么，简单概括，<strong>除主键索引以外的索引，都是二级索引</strong>，像我们平时建立的联合索引、前缀索引、唯一索引等。</p><p>二级索引的叶子节点存储的是索引值 + 主键 <code>id</code>。所以二级索引与聚簇索引的区别在于 <strong>叶子节点是否存放整行记录</strong>。</p><blockquote><p>也就意味着，仅仅靠二级索引无法拿到完整行数据，只能拿到 <code>id</code> 信息</p></blockquote><p>假设，我们有一个主键列为 <code>id</code> 的表，表中有字段 <code>k</code>，<code>k</code> 上有索引。</p><p>我们执行一条主键查询语句 <code>select * from T where id = 100</code>，只需要搜索 <code>id</code> 聚簇索引树就能查询整行数据。</p><p>接着再执行一条 <code>select * from T where k = 1</code>，此时要搜索 <code>k</code> 的二级索引树，具体过程如下：</p><ul><li>在 <code>k</code> 索引树上找 <code>k = 1</code> 的记录，取得 <code>id = 100</code></li><li>再到聚簇索引树查 <code>id = 100</code> 对应的行数据</li><li>回到 <code>k</code> 索引树取下一个值 <code>k = 2</code>，不满足条件，循环结束</li></ul><p>上述过程中，回到聚簇索引树搜索的过程，我们称为 <strong>回表</strong>。</p><blockquote><p>也就是说，基于二级索引的查询需要多扫描一棵聚簇索引树，因此在开发中尽量使用主键查询</p></blockquote><p>可是有时候我们确实需要使用二级索引查询，有没有办法避免回表呢？</p><p>办法是有的，但需要结合业务场景来使用，比如本次查询只返回 <code>id</code> 值，查询语句可以这样写 <code>select id from T where k = 1</code>，过程如下</p><ul><li>在 <code>k</code> 索引树上找 <code>k = 1</code> 的记录，取得 <code>id = 100</code></li><li>返回 <code>id</code> 值</li><li>回到 <code>k</code> 索引树取下一个值 <code>k = 2</code>，不满足条件，循环结束</li></ul><p>在这个查询中，索引 <code>k</code> 已经覆盖了我们的查询需求，不需要回表，这个操作称为<strong>覆盖索引</strong>。</p><blockquote><p>由于覆盖索引可以减少树的搜索次数，显著提升查询性能，所以使用覆盖索引是一个常用的性能优化手段</p></blockquote><p>假设现在有一个高频的业务场景，根据 <code>k</code> 查询，返回 <code>name</code>，我们可以把 <code>k</code> 索引变更成 <code>k</code> 与 <code>name</code> 的联合索引。</p><p><a href="https://mp.weixin.qq.com/s/yaza2iQ93BCvOW-uduS-yw" target="_blank" rel="noopener noreferrer">InnoDB原理篇：如何用好索引</a></p><p><a href="https://mp.weixin.qq.com/s?__biz=MzAwMDg2OTAxNg==&amp;mid=2652055534&amp;idx=1&amp;sn=6bce05f55b7a290a16e71d3885bfbaf0&amp;scene=21#wechat_redirect" target="_blank" rel="noopener noreferrer">InnoDB原理篇：聊聊数据页变成索引这件事</a></p><p>📒 一分钟看懂TCP粘包拆包</p><p>TCP 是一个面向「流」的协议，所谓流就是没有界限的一长串二进制数据。在实际的传输过程中，TCP 会根据网络情况将数据包进行拆分或者拼装，如果业务没有定义一个明确的界限规则，在应用层的业务上就会出现粘包拆包的现象。</p><p>针对 TCP 粘包拆包的现象，常见的解决思路如下：</p><ol><li>发送端给每个数据包 <strong>添加包首部</strong>。</li><li>发送端将每个数据包 <strong>封装为固定长度</strong>。</li><li>可以在数据包之间 <strong>设置边界</strong>。</li></ol><p>为了解决粘包拆包，Netty 框架也提供了很多开箱即用的编解码器，极大简化网络编程解决此类问题的难度。</p><p><a href="https://mp.weixin.qq.com/s/5lfw37ElEwG8aTeJvPbdeg" target="_blank" rel="noopener noreferrer">一分钟看懂TCP粘包拆包</a></p><p>📒 <a href="https://juejin.cn/post/7091486488201805861" target="_blank" rel="noopener noreferrer">什么是有区分度的好的面试问题，来看看字节跳动这道实现异步 sum 的问题</a></p><p>📒 <a href="https://juejin.cn/post/7091492741678366734" target="_blank" rel="noopener noreferrer">【前端部署第三篇】通过 docker 学习 nginx 配置，及基于 nginx 部署最简前端项目</a></p><p>📒 使用 CRA 搭建 React + TS 项目</p><p><a href="https://juejin.cn/post/7087811040591675428" target="_blank" rel="noopener noreferrer">都 2022 年了，手动搭建 React 开发环境很难吗</a></p><p><a href="https://juejin.cn/post/7039583726375796749" target="_blank" rel="noopener noreferrer">会写 TypeScript 但你真的会 TS 编译配置吗</a></p><p><a href="https://juejin.cn/post/7071066976830881823" target="_blank" rel="noopener noreferrer">用 Redux 做状态管理，真的很简单🦆</a></p><p><a href="https://juejin.cn/post/7069555976717729805" target="_blank" rel="noopener noreferrer">「React进阶」react-router v6 通关指南</a></p><p>📒 Usage With TypeScript - Redux Toolkit</p><p><a href="https://redux-toolkit.js.org/usage/usage-with-typescript" target="_blank" rel="noopener noreferrer">https://redux-toolkit.js.org/usage/usage-with-typescript</a></p><p>📒 全局状态和状态管理的区别</p><p>全局状态可以很简单，例如只要一个 JS 对象 <code>{}</code> 就可以实现，但是如果尝试修改全局状态的值，无法触发组件更新。</p><p>状态管理，除了具有全局状态的功能，还提供了一套发布订阅机制，即状态改变的时候通知对应组件更新。</p><p>Redux 本身其实就是全局状态，为了实现状态改变通知组件更新，还需要一个 UI-binding，即 React-redux。</p><p>📒 <a href="https://mp.weixin.qq.com/s/m_znGU_NaxveZi0Q5LSvyA" target="_blank" rel="noopener noreferrer">浅谈V8垃圾回收机制</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/5HqfRGqPyAhFt0krPgMHOQ" target="_blank" rel="noopener noreferrer">打造 Go 语言最快的排序算法</a></p><p>📒 <a href="https://juejin.cn/post/7091177467498463239" target="_blank" rel="noopener noreferrer">实现一个 Codepen：（二）在 Next.js 中使用 Monaco Editor</a></p><p>📒 <a href="https://juejin.cn/post/7091079487592333349" target="_blank" rel="noopener noreferrer">【架构师（第十八篇）】脚手架之项目模板的安装</a></p><p>📒 <a href="https://juejin.cn/post/7091103648100384804" target="_blank" rel="noopener noreferrer">【前端部署第二篇】基于 docker/compose 部署一个最简单的前端项目</a></p><p>📒 7 段小代码，玩转Java程序常见的崩溃场景</p><p>如何排查 CPU 飙升问题，获取问题代码通常可以使用下面的方法：</p><ol><li>使用 top 命令，查找到使用 CPU 最多的某个进程，记录它的 pid。使用 Shift + P 快捷键可以按 CPU 的使用率进行排序</li><li>再次使用 top 命令，加 -H 参数，查看某个进程中使用 CPU 最多的某个线程，记录线程的 ID</li><li>使用 printf 函数，将十进制的 tid 转化成十六进制</li><li>使用 jstack 命令，查看 Java 进程的线程栈</li><li>使用 less 命令查看生成的文件，并查找刚才转化的十六进制 tid，找到发生问题的线程上下文</li></ol><p><a href="https://mp.weixin.qq.com/s/YcyC1Jm4H7uGvSg3rCkDig" target="_blank" rel="noopener noreferrer">7 段小代码，玩转Java程序常见的崩溃场景</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ZralWEfG2WJfZ-G-x9biow" target="_blank" rel="noopener noreferrer">看完这篇你一定能掌握Linux</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/SHbt1jmgGaHQs1eeyJQ-qA" target="_blank" rel="noopener noreferrer">ObjectMapper，别再像个二货一样一直new了</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/bYtTRjqQylYKO9D1jbadSA" target="_blank" rel="noopener noreferrer">[<!-- -->科普<!-- -->]<!-- --> Service Worker 入门指南</a></p><p>📒 <a href="https://juejin.cn/post/7065693195799265287" target="_blank" rel="noopener noreferrer">百行代码带你实现通过872条Promise/A+用例的Promise</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/kpi82Rb66bUQuA_G0hrqBw" target="_blank" rel="noopener noreferrer">前端历史项目的 Vite 迁移实践总结</a></p><p>📒 <a href="https://juejin.cn/post/7090686619253997599" target="_blank" rel="noopener noreferrer">手写 css-modules 来深入理解它的原理</a></p><p>📒 在 Webpack 5 中开启懒编译（Lazy Compilation）</p><p>Webpack 5 的实验特性，可以针对多入口（Initial Chunk）和动态加载（Async Chunk）进行懒编译。开启懒编译之后，可以实现按需编译，提升启动速度，若再配合 Webpack 5 持久化缓存，则可以直接秒杀 Vite。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// …</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">experiments</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">lazyCompilation</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">imports</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">entries</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>由于实验特性具有相对宽松的语义版本，可能会有重大的变更，所以你需要锁定 Webpack 的小版本号，例如 <code>"webpack": "~5.4.3"</code>，或者锁定版本号</p></blockquote><p><a href="https://juejin.cn/post/7090372816784064526" target="_blank" rel="noopener noreferrer">在 Webpack 5 中开启懒编译（Lazy Compilation）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Ba-3fMQXNXqIzVTjVUrWtQ" target="_blank" rel="noopener noreferrer">浅谈文档的实时协同编辑</a></p><p>📒 腾讯一面：CORS为什么能保障安全？为什么只对复杂请求做预检</p><p>首先为什么要有同源策略？浏览器需要记住用户的登录状态（即登录凭证），这样用户下次访问页面就无需重复登录。这样的话，就需要有一些安全策略，否则很容易出现 CSRF 攻击等问题。如果是其他的 http client 则没有同源策略。</p><blockquote><p>CORS策略的心智模型是：所有跨域请求都是不安全的，浏览器要带上来源给服务器检验</p></blockquote><p>同源策略会限制哪些行为：</p><ul><li>跨域情况下获取 DOM 元素（例如跨域的 <code>iframe</code>）、localStorage、Cookie 等</li><li>跨域情况下发送 ajax 请求，浏览器会拒绝解析响应报文</li></ul><blockquote><p>注意，浏览器默认的表单提交不受同源策略限制</p></blockquote><p>CORS 即跨域资源共享，这里注意 CORS 的目的不是拦截请求，反倒是为了让其能正常请求。CORS 的诞生背景就是同源策略，这是一个相当严苛的规定，它禁止了跨域的AJAX请求。但实际的开发中又有这样的需求，于是开一个口子——只要配置了CORS的对应规则，跨域请求就能正常进行。</p><p>如何配置 CORS？前端在发送请求的时候，浏览器会在请求头添加 <code>Origin</code> 字段，这样后端就能知道请求的来源，然后后端在响应头添加 <code>Access-Control-Allow-Origin</code>，这个值就是前端发送的来源地址（或者直接加 <code>*</code> 表示允许所有地址）。</p><p>跨域请求的流程，CORS把请求分成简单请求和复杂请求，划分的依据是“是否会产生副作用”。同时满足下面这两个条件的是 <strong>简单请求</strong>，否则就是 <strong>非简单请求</strong>：</p><ul><li>请求方法是 HEAD/GET/POST</li><li>请求体的 Conent-Type 只能是 <code>form-urlencoded</code>、<code>form-data</code>、<code>text/plain</code></li></ul><p>对于简单请求，流程如下：</p><ol><li>浏览器发起请求，并且自动加上请求的来源 <code>origin</code> 给服务器检查；</li><li>服务器返回数据，并返回检查结果，配置CORS响应头；</li><li>浏览器检查CORS响应头，如果包含了当前的源则放行，反之拦截；</li></ol><blockquote><p>这里需要注意，浏览器是拦截响应，而不是拦截请求，跨域请求是发出去的，并且服务端做了响应，只是浏览器拦截了下来</p></blockquote><p>对于复杂请求，流程如下：</p><ol><li>浏览器发起预检请求，带上请求的来源 <code>origin</code>，不包含请求体；</li><li>服务器返回检查结果，配置CORS头；</li><li>浏览器发起真正请求；</li><li>浏览器返回数据；</li></ol><blockquote><p>浏览器会检查第2步中拿到的CORS头，如果没有包含当前的源，后续的第3、4步都不会进行，也就是不会发起真正请求</p></blockquote><p>为什么只对复杂请求做预检？上文提到，划分简单请求和复杂请求的依据是“是否产生副作用”。这里的副作用指对 <strong>数据库做出修改</strong>：使用GET请求获取新闻列表，数据库中的记录不会做出改变，而使用PUT请求去修改一条记录，数据库中的记录就发生了改变。</p><p>假设网站被CSRF攻击了——黑客网站向银行的服务器发起跨域请求，并且这个银行的安全意识很弱，只要有登录凭证cookie就可以成功响应，考虑下面两种情况：</p><ul><li>黑客网站发起一个GET请求，目的是查看受害用户本月的账单。银行的服务器会返回正确的数据，不过影响并不大，而且由于浏览器的拦截，最后黑客也没有拿到这份数据；</li><li>黑客网站发起一个PUT请求，目的是把受害用户的账户余额清零。浏览器会首先做一次预检，发现收到的响应并没有带上CORS响应头，于是真正的PUT请求不会发出；</li></ul><p>幸好有预检机制，否则PUT请求一旦发出，黑客的攻击就成功了。</p><blockquote><p>这种情况下，后端也需要遵循 RESTful 规范，否则要么面临攻击风险，要么会多发一次预检请求</p></blockquote><p><a href="https://juejin.cn/post/7081539471585312805" target="_blank" rel="noopener noreferrer">腾讯一面：CORS为什么能保障安全？为什么只对复杂请求做预检</a></p><p><a href="https://juejin.cn/post/7087206796351242248" target="_blank" rel="noopener noreferrer">腾讯三面：Cookie的SameSite了解吧，那SameParty呢</a></p><p>📒 Axios 三个优点</p><ul><li>Promisify</li><li>责任链（拦截器机制）</li><li>适配器（同时支持浏览器和 node 环境）</li></ul><p>📒 <a href="https://mp.weixin.qq.com/s/_gDIO6YCswAS2dICllMG0A" target="_blank" rel="noopener noreferrer">深入理解 Promise 之手把手教你写一版</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ckskF06PD43KHpKAGaYmRA" target="_blank" rel="noopener noreferrer">2022 年 JavaScript 开发工具的生态</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/-WHafu5z-Ap4tjrbWesnmA" target="_blank" rel="noopener noreferrer">自动化生成骨架屏的技术方案设计与落地</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[4月24日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月24日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月24日内容汇总"/>
        <updated>2022-04-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Ubuntu 22.04 LTS 安装]]></summary>
        <content type="html"><![CDATA[<p>📒 Ubuntu 22.04 LTS 安装</p><p><a href="https://phoenixnap.com/kb/ubuntu-22-04-lts" target="_blank" rel="noopener noreferrer">https://phoenixnap.com/kb/ubuntu-22-04-lts</a></p><p><a href="https://releases.ubuntu.com/jammy/" target="_blank" rel="noopener noreferrer">https://releases.ubuntu.com/jammy/</a></p><p>📒 计算机程序的构造和解释 — JavaScript 版</p><p>这本由麻省理工学院出版的著作终于有了 JavaScript 语言版本，可以帮助你建立对计算机程序的心智模型。</p><blockquote><p><a href="https://github.com/source-academy/sicp" target="_blank" rel="noopener noreferrer">https://github.com/source-academy/sicp</a></p></blockquote><p>📒 为什么要使用 Redux Toolkit</p><p>Redux 官方发布的这篇博客讲解了 Redux Toolkit 的 Why 和 How，并强烈推荐使用。</p><p>一句话总结：Redux Toolkit 是使用 Redux 的最佳实践。</p><blockquote><p><a href="https://redux.js.org/introduction/why-rtk-is-redux-today" target="_blank" rel="noopener noreferrer">https://redux.js.org/introduction/why-rtk-is-redux-today</a></p></blockquote><p>⭐️ <a href="https://zhuanlan.zhihu.com/p/502951532" target="_blank" rel="noopener noreferrer">Node.js 18 新特性解读</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/415361629" target="_blank" rel="noopener noreferrer">那些你应该说再见的 npm 祖传老库</a></p><p>📒 如何实现数组转对象</p><p>传入一个 <code>paramKeys</code> 数组，获取 query 参数的值，然后以对象形式返回，使用 <code>reduce</code> 方法：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paramKeys</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> searchParams </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">URLSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">location</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">search</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> paramKeys</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-function function" style="color:#d73a49">reduce</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Record</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name builtin">string</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">,</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name builtin">string</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">accu</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    accu</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> searchParams</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> accu</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> searchParams </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'name'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'age'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>以上流程还可以封装成自定义 hook：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> React </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paramKeys</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> query </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">location</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">search</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">useMemo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> searchParams </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">URLSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">query</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> paramKeys</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-function function" style="color:#d73a49">reduce</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Record</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name builtin">string</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">,</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name builtin">string</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">accu</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      accu</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> searchParams</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cur</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> accu</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">paramKeys</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> query</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>看了 antfu 大佬的代码，还可以使用 <code>Object.fromEntries()</code> 方法：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paramKeys</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> searchParams </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">URLSearchParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">location</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">search</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fromEntries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    paramKeys</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> searchParams</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>注意：<code>Object.fromEntries()</code> 是 ES2019 中的语法，存在兼容性问题（Chrome &gt;= 73），不过只要正确配置 polyfill 就可以放心使用</p></blockquote><p>📒 使用 <code>defineConfig</code> 约束配置对象</p><p>在项目中经常需要用到配置对象，例如 Webpack、rollup 的配置，我们可以使用 TS 来约束配置对象的 API schema，告知用户应该传哪些字段以及对应的类型，这样有两个好处：</p><ul><li>对用户更加友好，不需要看文档就能直接上手</li><li>在开发阶段就能提前检查出配置项错误，不用到运行阶段再去校验了</li></ul><p>一般来说我们需要导出一个接口类型：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">IConfig</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  age</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  sex</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>用户在使用的时候需要导入类型，然后自己添加注解，这样编写配置对象就能得到类型提示了：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> IConfig </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"xxx"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> config</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> IConfig</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dbydm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    age</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">23</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>但是这样对用户来说还是太麻烦了，我们可以定义一个 <code>defineConfig</code> 函数，这个函数做的事情很简单，就是把接收到的参数原封不动地返回，但在这个过程中，就可以实现参数类型的校验：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">IConfig</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  age</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  sex</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">defineConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">config</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> IConfig</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>用户只需导入 <code>defineConfig</code> 编写配置就可以实现参数类型的校验：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> defineConfig </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"xxx"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">defineConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dbydm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    age</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">23</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/GG_zrQlaiP2nfPOxzx_j9w" target="_blank" rel="noopener noreferrer">Elasticsearch 基础入门详文</a></p><p>📒 <a href="https://juejin.cn/post/7086735198942920712" target="_blank" rel="noopener noreferrer">如何把前端项目写成一座屎山</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/uxSoXkmi5KIGNPsyd5cXrA" target="_blank" rel="noopener noreferrer">浅谈JS内存机制</a></p><p>📒 <a href="https://juejin.cn/post/7087933643821154312" target="_blank" rel="noopener noreferrer">深入理解 scheduler 原理</a></p><p>📒 前端框架如何实现预渲染</p><p>首先预渲染根据渲染时机分为以下两种：</p><ul><li>静态站点生成（SSG），构建的时候获取数据进行渲染，数据不一定是最新的</li><li>服务端渲染（SSR），用户访问的时候服务端获取数据进行渲染，数据实时获取</li></ul><blockquote><p>两种渲染方案都可以实现 <strong>首屏性能优化</strong>、<strong>SEO 优化</strong>，不同的是 SSR 需要在服务端运行 JS，并且每次用户请求的时候都会进行渲染；SSG 已经将每个页面渲染成静态 html，因此可以将资源托管到 CDN 上</p></blockquote><p>获取数据又可以分为以下几种方式：</p><ul><li>本地文件系统读取</li><li>调接口获取</li><li>查询数据库获取</li></ul><p>实际上，React 本身已经提供了服务端渲染和静态生成相关的 API。在前端项目中，我们一般会使用下面的 API 挂载 React 组件：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">element</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> container</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> callback</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>为了实现 SSR 渲染，我们可以使用下面的 API 将 React 组件直接渲染为 HTML 字符串：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token maybe-class-name">ReactDOMServer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">renderToString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">element</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>使用 <code>renderToString</code> 方法渲染出的 HTML 字符串会带有特定标记，我们可以使用下面的 API 在客户端进行激活，对标记的节点挂载相应的事件监听器：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">hydrate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">element</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> container</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> callback</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在 SSG 渲染中，我们不需要在客户端进行激活，因此不用在 HTML 字符串中添加标记，只需渲染出纯的 HTML 字符串：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token maybe-class-name">ReactDOMServer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">renderToStaticMarkup</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">element</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/6938385978004340744" target="_blank" rel="noopener noreferrer">2万字系统总结，带你实现 Linux 命令自由</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/ebCRE9RXB66X0pe4lsX0tg" target="_blank" rel="noopener noreferrer">还在手撸 Nginx 配置？试试这款可视化配置工具吧，真心强大</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/3aVYGfahv5rZJbWBhaI3BA" target="_blank" rel="noopener noreferrer">esno，基于 Esbuild 的神器</a></p><p>📒 「React进阶」换个姿势看 hooks ！ 灵感来源组合和HOC 模式下逻辑视图分离新创意</p><p><code>useMemo</code> 类似 Vue 中的计算属性，当依赖项发生变化，会重新计算。但实际上 <code>useMemo</code> 比计算属性更强大，除了缓存值之外，还能缓存组件：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Index</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> value </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setNumber</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> element </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useMemo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Test</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">element</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">setNumber</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">number </span><span class="token tag script language-javascript operator" style="color:#393A34">+</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript number" style="color:#36acaa">1</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">点击 </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">number</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>有时候在父组件定义的事件处理函数，需要作为 prop 传入子组件。如果父组件重新渲染，会导致函数重新生成，相当于 prop 发生变化，即使子组件内部使用 <code>React.memo()</code> 包裹也会导致重新渲染。常规做法是使用 <code>React.useCallback()</code> 包裹事件处理函数，但实际上用 <code>React.useRef()</code> 包裹也是可以的，都是把事件处理函数缓存到 Fiber 节点上。</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">MyApp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> onClickRef </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"666"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// const onClick = React.useCallback(() =&gt; {}, []);</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">h1</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">Welcome to my app</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">h1</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">MyButton</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">onClickRef</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">current</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://juejin.cn/post/7088829366490120205" target="_blank" rel="noopener noreferrer">「React进阶」换个姿势看 hooks ！ 灵感来源组合和HOC 模式下逻辑视图分离新创意</a></p><p>📒 React 18 升级踩坑汇总</p><p><strong>1. React.StrictMode 导致所有组件重复挂载两次</strong></p><p>使用 CRA 5.0.1 搭建 React 项目，默认的项目模板中，根组件使用了 <code>React.StrictMode</code> 包裹，结果出现了所有组件都重复挂载的情况，导致组件中接口调了两次。看了下文档，确实是 React 18 中引入的 Breaking Change，启用严格模式，会导致所有组件重复挂载两次（即使用了 <code>React.memo</code> 也会重复挂载）：</p><blockquote><p>Stricter Strict Mode: In the future, React will provide a feature that lets components preserve state between unmounts. To prepare for it, React 18 introduces a new development-only check to Strict Mode. React will automatically unmount and remount every component, whenever a component mounts for the first time, restoring the previous state on the second mount. If this breaks your app, consider removing Strict Mode until you can fix the components to be resilient to remounting with existing state</p></blockquote><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>使用 CRA 创建的 React 18 项目，建议移除 <code>React.StrictMode</code></p></div></div><p><strong>2. React 18 中使用了 antd 的 message 组件控制台打印警告信息</strong></p><p>React 18 使用了新的 <code>ReactDOM.createRoot()</code> API 挂载根节点，Concurrent Mode 需要通过此 API 开启，但是 antd 中的 message 等组件内部仍使用 <code>ReactDOM.render()</code> 挂载根节点，此时在控制台会打印警告，注意这并不是报错，仅仅只是 fallback 到 legacy mode 而已。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>升级前最好仔细看一遍官方的说明，特别是 Breaking Change：</p><blockquote><p><a href="https://github.com/facebook/react/releases/tag/v18.0.0" target="_blank" rel="noopener noreferrer">https://github.com/facebook/react/releases/tag/v18.0.0</a></p></blockquote></div></div><p>📒 为什么需要 peerDependencies</p><p>例如开发一个 React 组件库的时候，有三个诉求：</p><ul><li>该组件库开发的时候需要安装 React；</li><li>用户引入该组件库的时候不能重复安装 React；</li><li>组件库的 React 版本与目标环境不一致的时候需要被包管理器发现并打印警告；</li></ul><p>如果安装到 dependencies 下，显然会导致重复安装；如果安装到 devDependencies 下虽然不会导致重复安装，但包管理器不会检查版本，当版本不一致的时候不会打印警告。所以 peerDependencies 是最优选择。</p><blockquote><p>在老版本 React 项目中引入某些依赖库（例如 <code>antd</code>、<code>react-transition-group</code>），一般不能直接安装最新的版本（大概率会报错），此时应该根据依赖库的 package.json 中指定的 <code>peerDependencies</code> 字段选择合适的依赖库版本</p></blockquote><p>⭐️ 什么是 JavaScript 的函数组合</p><p>本篇文章以一个简略的 Markdown 的例子为主线，讲述了什么是函数组合，以及如何使用函数组合的思想编写代码，是一篇非常不错的编程思想类文章。</p><blockquote><p><a href="https://jrsinclair.com/articles/2022/javascript-function-composition-whats-the-big-deal/" target="_blank" rel="noopener noreferrer">https://jrsinclair.com/articles/2022/javascript-function-composition-whats-the-big-deal/</a></p></blockquote><p>📒 <a href="https://segmentfault.com/a/1190000041683421" target="_blank" rel="noopener noreferrer">一些关于react的keep-alive功能相关知识在这里(下)</a></p><p>📒 <a href="https://segmentfault.com/a/1190000041683300" target="_blank" rel="noopener noreferrer">一些关于react的keep-alive功能相关知识在这里(上)</a></p><p>📒 <a href="https://juejin.cn/post/7088417070009810981" target="_blank" rel="noopener noreferrer">理清 HTTP 下的 TCP 流程，让你的 HTTP 水平更上一层</a></p><p>📒 React 18 系列</p><p><a href="https://mp.weixin.qq.com/s/t3dYc3Md1dpiv1vaFa5plA" target="_blank" rel="noopener noreferrer">React 18 全览</a></p><p><a href="https://mp.weixin.qq.com/s/fgT7Kxs_0feRx4TkBe6G5Q" target="_blank" rel="noopener noreferrer">React 18 对 Hooks 的影响</a></p><p><a href="https://mp.weixin.qq.com/s/GatHpP3BRLV_I48MfpzR4A" target="_blank" rel="noopener noreferrer">React 的心智模型</a></p><p><a href="https://mp.weixin.qq.com/s/qyr6MnPtvnELDSbPJ2VtIw" target="_blank" rel="noopener noreferrer">你不知道的 React v18 的任务调度机制</a></p><p>📒 React 几个小技巧</p><p><strong>1. React 内置工具类型</strong></p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 使用 React.ComponentType 同时表示类组件和函数组件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ComponentType</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">P</span><span class="token class-name"> </span><span class="token class-name operator" style="color:#393A34">=</span><span class="token class-name"> </span><span class="token class-name punctuation" style="color:#393A34">{</span><span class="token class-name punctuation" style="color:#393A34">}</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> ComponentClass</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">P</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> FunctionComponent</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">P</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用 React.Key 来表示列表渲染 key 的类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Key</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>参考：</p><p><a href="https://juejin.cn/post/6844904122550845448" target="_blank" rel="noopener noreferrer">精读《@types react 值得注意的 TS 技巧》</a></p><p><a href="https://juejin.cn/post/7079449083919728671" target="_blank" rel="noopener noreferrer">从 @types/react 的类型定义中，我学到了什么</a></p><p><a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts" target="_blank" rel="noopener noreferrer">https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts</a></p><p><strong>2. 自定义组件如何绑定 className</strong></p><p>将 <code>className</code> 作为 prop 传入，内部使用 classnames 这个库进行拼接：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">cx</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"classnames"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">s</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./style.module.less"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">IProps</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  className</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FC</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">IProps</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> className </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">className</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript function" style="color:#d73a49">cx</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">s</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">wrapper</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"> className</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>更进一步，把以上流程封装成高阶组件（HOC）：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">withClassName</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token maybe-class-name">Component</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">ComponentType</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FC</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> className</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> className</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">restProps </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">className</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">className</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Component</span><span class="token tag" style="color:#00009f"> </span><span class="token tag spread punctuation" style="color:#393A34">{</span><span class="token tag spread operator" style="color:#393A34">...</span><span class="token tag spread" style="color:#00009f">restProps</span><span class="token tag spread punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>3. Input 如何变为受控组件</strong></p><p>Antd 中的 Input 默认是非受控组件，可以绑定 <code>value</code>，然后监听 <code>onChange</code> 修改 <code>value</code> 实现受控（<code>v-model</code> 的原理）：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FC</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">num</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setNum</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">InputNumber</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">value</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">num</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onChange</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">setNum</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/7085674288933502984" target="_blank" rel="noopener noreferrer">我帮一朋友重构了点代码，他直呼牛批，但基操勿六</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/imxPGpN_EXq4St_EpcA2eg" target="_blank" rel="noopener noreferrer">React + TypeScript：如何处理常见事件</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Ua03qsLcrVURtxhSnuU_6w" target="_blank" rel="noopener noreferrer">单例模式 4 种经典实现方法</a></p><p>📒 如何实现 <code>useClickAway</code></p><p>如何监听元素外的点击，类似 Vue 的 ClickOutSide 指令</p><blockquote><p>官方文档：<a href="https://ahooks.js.org/hooks/use-click-away" target="_blank" rel="noopener noreferrer">https://ahooks.js.org/hooks/use-click-away</a></p></blockquote><blockquote><p>源码：<a href="https://github.com/alibaba/hooks/blob/master/packages/hooks/src/useClickAway/index.ts" target="_blank" rel="noopener noreferrer">https://github.com/alibaba/hooks/blob/master/packages/hooks/src/useClickAway/index.ts</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7087906504308850701" target="_blank" rel="noopener noreferrer">快速理解 TypeScript 的逆变、协变</a></p><p>📒 <a href="https://juejin.cn/post/7087811040591675428" target="_blank" rel="noopener noreferrer">都 2022 年了，手动搭建 React 开发环境很难吗</a></p><p>📒 <a href="https://juejin.cn/post/7085298532365631501" target="_blank" rel="noopener noreferrer">这篇手写 Promise 你一定要康康</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/JZbsIqsqNeJmc__QFKpo1Q" target="_blank" rel="noopener noreferrer">超全面的前端新一代构建工具对比: esbuild、Snowpack、Vite、wmr</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[4月17日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月17日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月17日内容汇总"/>
        <updated>2022-04-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 JS 相关技巧]]></summary>
        <content type="html"><![CDATA[<p>📒 JS 相关技巧</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 1. 数组转对象</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> dict</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fromEntries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2. 使用 Array.from 初始化数组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> digits </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> length</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 3. 字符串转数组，然后用数组方法遍历</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 常规方法是用 split()</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">String</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 由于字符串实现了 iterator 接口，因此可以使用扩展运算符展开到数组中</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">...</span><span class="token function" style="color:#d73a49">String</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">...</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://zhuanlan.zhihu.com/p/417534662" target="_blank" rel="noopener noreferrer">用Rust锈化Vue Compiler</a></p><p>📒 TS 类型体操性能分析</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tsc index.ts –-diagnostics</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 前端动画实现方案</p><ul><li>CSS 方案：<code>transition</code>、<code>animation</code></li><li>JS 方案：<code>setTimeout</code>、<code>requestAnimationFrame</code></li></ul><p>一个实验性 API <code>Element.animate()</code>，可以在渲染进程的时候就执行，性能更好。</p><blockquote><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Element/animate" target="_blank" rel="noopener noreferrer">https://developer.mozilla.org/zh-CN/docs/Web/API/Element/animate</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7085257325165936648" target="_blank" rel="noopener noreferrer">我是如何带领团队从零到一建立前端规范的</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/250493093" target="_blank" rel="noopener noreferrer">血泪教训之请不要再轻视Git —— 我在工作中是如何使用 Git 的</a></p><p>📒 <a href="https://nextjs.org/learn/basics/create-nextjs-app" target="_blank" rel="noopener noreferrer">https://nextjs.org/learn/basics/create-nextjs-app</a></p><p>📒 <a href="https://nextjs.org/docs" target="_blank" rel="noopener noreferrer">https://nextjs.org/docs</a></p><p>📒 <a href="https://juejin.cn/post/6844903944343273485" target="_blank" rel="noopener noreferrer">手把手教你用神器nextjs一键导出你的github博客文章生成静态html</a></p><p>📒 Golang 三数之和</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">package</span><span class="token plain"> algorithm</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"sort"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ThreeSum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ans </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">make</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 数组元素个数小于 3，直接返回</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> ans</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 排序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    sort</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Ints</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 遍历到倒数第二个，因为是三个数总和</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 规定 nums[i] &lt; nums[left] &lt; nums[right]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 如果 nums[i] &gt; 0 则不存在另外两个值使得相加等于 0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 大于 0 可以直接跳出循环了</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">break</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 过滤 nums[i] 重复</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">continue</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 先确定一个值 nums[i]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 再去找另外两个值 nums[left] 和 nums[right]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 需要满足 nums[i] &lt; nums[left] &lt; nums[right]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        target </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        left</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 使用双指针法确定剩下两个值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> left </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> right </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            sum </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> sum </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> target </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                left</span><span class="token operator" style="color:#393A34">++</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> sum </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> target </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                right</span><span class="token operator" style="color:#393A34">--</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> sum </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> target </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                ans </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ans</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 找到目标值，左右指针分别移动一位</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                left</span><span class="token operator" style="color:#393A34">++</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                right</span><span class="token operator" style="color:#393A34">--</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 过滤 nums[left] 重复</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> left </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">left</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    left</span><span class="token operator" style="color:#393A34">++</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 过滤 nums[right] 重复</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> left </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">right</span><span class="token operator" style="color:#393A34">+</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    right</span><span class="token operator" style="color:#393A34">--</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> ans</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Golang 手写数组方法</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">package</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"fmt"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fn </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">range</span><span class="token plain"> nums </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">fn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fn </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    res </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">make</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">range</span><span class="token plain"> nums </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fn </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">bool</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    res </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">make</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">range</span><span class="token plain"> nums </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> res</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fn </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> initValue </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    res </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> initValue</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">range</span><span class="token plain"> nums </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> res</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    s </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">{</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">ForEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"===forEach"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    mapped </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> item </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mapped</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    filtered </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">bool</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> item </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">filtered</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    reduced </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">accu</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> index </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> accu </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> cur</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">reduced</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/kGMsNmIXlT25NfRrifjnTQ" target="_blank" rel="noopener noreferrer">选择第三方 NPM 包时的 5 条最佳实践</a></p><p>📒 <a href="https://juejin.cn/post/7072321805792313357" target="_blank" rel="noopener noreferrer">Vue3.2 vDOM diff流程分析之一：diff算法</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/pNossFUtJrDHshXbWLb4vA" target="_blank" rel="noopener noreferrer">从零到一，我们来一起造个 JS 的编译器</a></p><p>⭐️ <a href="https://juejin.cn/post/7085542534943883301" target="_blank" rel="noopener noreferrer">2022 年的 React 生态</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/163481957" target="_blank" rel="noopener noreferrer">linux后台开发具备能力集锦</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/439279854" target="_blank" rel="noopener noreferrer">Linux下C++后台服务器开发</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/471317280" target="_blank" rel="noopener noreferrer">Go 语言与并发编程</a></p><p>📒 <a href="https://juejin.cn/post/7085224136980561927" target="_blank" rel="noopener noreferrer">打造轻量级 WebIDE，看这一篇文章就够啦</a></p><p>📒 developer-roadmap</p><p>developer-roadmap 是一个开发人员路线图，包含了前端路线图、后端路线图、DevOps 路线图、React 路线图、Angular 路线图、Android 路线图、Python 路线图、Go 路线图、Java 路线图、DBA 路线图。</p><blockquote><p><a href="https://github.com/kamranahmedse/developer-roadmap" target="_blank" rel="noopener noreferrer">https://github.com/kamranahmedse/developer-roadmap</a></p></blockquote><p>📒 <a href="https://github.com/vercel/pkg" target="_blank" rel="noopener noreferrer">pkg: 把 Node.js 项目打包为可执行文件</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[4月10日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月10日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月10日内容汇总"/>
        <updated>2022-04-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 编译 ts 代码用 tsc 还是 babel]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7084882650233569317" target="_blank" rel="noopener noreferrer">编译 ts 代码用 tsc 还是 babel</a></p><p>📒 第三方库是否应该提交 lockfile</p><p>在业务项目中，每次依赖安装的版本号都从 lock 文件中进行获取，锁定依赖和依赖的依赖，避免了不可测的依赖风险。但是仍然存在间接依赖不可控的问题，例如 React 依赖 object-assign，在 React 中 lockfile 锁定的版本为 <code>object-assign@4.1.0</code>，但是前端项目实际安装的版本为 <code>object-assign@4.99.99</code>。</p><ul><li>第三方库的 <code>devDependencies</code> 必须锁定，这样 Contributor 可根据 lockfile 很容易将项目跑起来</li><li>第三方库的 <code>dependencies</code> 虽然有可能存在不可控问题，但是可通过锁死依赖或者勤加更新的方式来解决</li></ul><p><a href="https://juejin.cn/post/7031122959637217310" target="_blank" rel="noopener noreferrer">如果没有 package-lock.json，那将如何</a></p><p>📒 工程化知识卡片 023：node_modules 版本重复的困境</p><p>在 <code>npmv3</code> 之后 <code>node_modules</code> 为平铺结构，但是仍然存在依赖重复安装的问题。</p><p><a href="https://juejin.cn/post/7030084290989948935s" target="_blank" rel="noopener noreferrer">工程化知识卡片 023：node_modules 版本重复的困境</a></p><p>📒 Vue 开发小技巧</p><p><a href="https://juejin.cn/post/7084536432731095048" target="_blank" rel="noopener noreferrer">分享 15 个 Vue3 全家桶开发的避坑经验</a></p><p><a href="https://juejin.cn/post/7080875763162939429" target="_blank" rel="noopener noreferrer">vue3中可以帮助你早点下班的9个开发技巧</a></p><p>📒 <a href="https://juejin.cn/post/7083468345579667493" target="_blank" rel="noopener noreferrer">【混淆系列】三问：npx、npm、cnpm、pnpm区别你搞清楚了吗？</a></p><p>📒 <a href="https://juejin.cn/post/7082738107237433375" target="_blank" rel="noopener noreferrer">Webpack组件库打包超详细指南</a></p><p>📒 Node.js 技术架构</p><p>Node 是怎么实现的？简言之：用 V8 运行 JS、用 bindings 实现 JS 与 C/C++ 沟通、用 C/C++ 库高效处理 IO、用 Node.js 标准库简化 JS 代码、用 Event Loop 管理事件处理顺序、用 libuv 实现异步 I/O 操作。</p><p><a href="https://juejin.cn/post/7081891057918558221" target="_blank" rel="noopener noreferrer">Node.js 技术架构</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/_eDFlWBJHxf4oar6Fpye2Q" target="_blank" rel="noopener noreferrer">Web 框架的替代方案</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/XWZsKQECcsHAlE9cyqi9Eg" target="_blank" rel="noopener noreferrer">写好 JavaScript 异步代码的几个推荐做法</a></p><p>📒 Node.js 进阶 - 多文件 Stream 合并，串行和并发两种模式实现</p><p>重要的事情再说一遍，<code>pipe</code> 方法默认情况下会自动关闭可写流，但是如果可读流期间发生错误，则写入的目标流将不会关闭，所以如果使用 <code>pipe</code> 需要监听错误事件，手动关闭可写流，防止文件句柄泄露。</p><p><a href="https://mp.weixin.qq.com/s/WisEGFz2yn_ZeekViofMnA" target="_blank" rel="noopener noreferrer">Node.js 进阶 - 多文件 Stream 合并，串行和并发两种模式实现</a></p><p>📒 <a href="https://juejin.cn/post/7046898330000949285" target="_blank" rel="noopener noreferrer">服务端渲染SSR及实现原理</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/lyff2svfHh4rdsWRL4H5uA" target="_blank" rel="noopener noreferrer">手摸手服务端渲染-react</a></p><p>📒 <a href="https://juejin.cn/post/7058868160706904078" target="_blank" rel="noopener noreferrer">如何在项目中用好 TypeScript</a></p><p>📒 Golang 和 JS 创建对象方式对比</p><p>Golang 与 JS 创建对象非常类似，Golang 在创建对象的时候需要定义 schema 进行类型约束：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Person </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Name    </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Age     </span><span class="token builtin">int</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Sex     </span><span class="token builtin">bool</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">person </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> Person</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dbydm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Age</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">12</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Sex</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Golang 创建对象数组：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">list </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">Person</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">Person</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dbydm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Age</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">12</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Sex</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">Person</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Age</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2333</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Sex</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Node.js 常见的系统信号</p><ul><li>SIGHUP：不通过 ctrl+c 停止进程，而是直接关闭命令行终端，会触发该信号</li><li>SIGINT：按下 ctrl+c 停止进程时触发；pm2 重启或者停止子进程时，也会向子进程发送该信号</li><li>SIGTERM：一般用于通知进程优雅退出，如 k8s 删除 pod 时，就会向 pod 发送 SIGTERM 信号，pod 可以在超时时间内（默认 30s）做一些退出清理动作</li><li>SIGBREAK：在 window 系统上，按下 ctrl+break 会触发该信号</li><li>SIGKILL：强制退出进程，进程无法做任何清理动作，执行命令 kill -9 pid，进程会收到该信号。k8s 删除 pod 时，如果超过 30s，pod 还没退出，k8s 会向 pod 发送 SIGKILL 信号，立即退出 pod 进程；pm2 在重启或者停止进程时，如果超过 1.6s，进程还没退出，也会发送 SIGKILL 信号</li></ul><p>📒 <a href="https://mp.weixin.qq.com/s/JCIyV-_VfQ9iScd_xOuP8g" target="_blank" rel="noopener noreferrer">2022 年，Babel vs TypeScript，谁更适合代码编译</a></p><p>📒 React 常用状态管理库</p><ul><li>Redux</li><li>Mobx</li><li>Recoil</li><li>Hookstate</li><li>Rematch</li><li>Jotai</li><li>Zustand</li></ul><p>📒 <a href="https://juejin.cn/post/7083230365027926053" target="_blank" rel="noopener noreferrer">从源码理清 useEffect 第二个参数是怎么处理的</a></p><p>📒 <a href="https://juejin.cn/post/7081539471585312805" target="_blank" rel="noopener noreferrer">腾讯一面：CORS为什么能保障安全？为什么只对复杂请求做预检？</a></p><p>📒 如何在 Node 环境使用 ESM 模块规范</p><p>首先明确一点，Node 环境并非不支持 ESM 规范，只是没有启用而已，默认使用 CJS 规范，可通过如下方式启用：</p><ul><li>单文件使用 ESM 规范，可以将该文件后缀改为 <code>.mjs</code>；</li><li>整个工程使用 ESM 规范，可以在 <code>package.json</code> 中配置 <code>"type": "module"</code>；</li></ul><p>假如不想通过上述方式启用，还有一些方法：</p><ul><li>通过 Webpack 等打包工具支持 ESM 模块（Webpack 默认使用 <code>web</code> 环境构建，需要配置 <code>target: "node"</code> 避免打包 Node 内置模块）；</li><li>还可以使用 <code>ts-node</code>、<code>jiti</code> 等 runtime 支持 ESM 模块（内部使用 <code>tsc</code> 或者 <code>babel</code> 进行编译）；</li></ul><p>📒 如何生成随机 ID</p><p>一种是直接使用 <code>Math.random()</code>：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">randomId</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token known-class-name class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>另一种是使用查表的方式：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 生成 [0..9] 的数组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> nums </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">length</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">_</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 从 nums 数组中随机选取元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">sample</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">arr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">[</span><span class="token known-class-name class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">floor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token known-class-name class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">random</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">randomId</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token known-class-name class-name">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">length</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">6</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">sample</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 跨域如何携带 Cookie</p><ul><li>如果通过网关层代理（例如 nginx）则不用担心，对于浏览器来说实际上并没有跨域，可正常携带 Cookie</li><li>如果通过 CORS 跨域，浏览器默认不会携带 Cookie，此时有两种方案：<ul><li>在请求头中添加 <code>Authorization</code> 字段发送 Cookie（在 axios 中配置请求拦截添加）</li><li>后端响应头添加 <code>Access-Control-Allow-Credentials</code>，前端发送请求时配置 <code>xhr.withCredentials = true</code></li></ul></li></ul>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[4月3日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月3日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/4月3日内容汇总"/>
        <updated>2022-04-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 rollup 配置优化方案]]></summary>
        <content type="html"><![CDATA[<p>📒 rollup 配置优化方案</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 打包引用主入口文件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> appIndex </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"ESM"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"CJS"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">format</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">input</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'index.js'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  format</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">external</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"./pyodide.worker.js"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">output</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">file</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'dist/client'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'env.mjs'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">sourcemap</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 打包 worker 文件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 目的是让 rollup 也处理下这个文件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> worker </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">input</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'pyodide.worker.js'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">output</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">file</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'dist/client'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'pyodide.worker.js'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">sourcemap</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">appIndex</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">worker</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Git merge 三种策略</p><ul><li><code>git merge</code>：默认使用 fast-forward 方式，git 直接把 HEAD 指针指向合并分支的头，完成合并。属于“快进方式”，不过这种情况如果删除分支，则会丢失分支信息。因为在这个过程中没有创建 commit</li><li><code>git merge --no-ff</code>：强行关闭 fast-forward 方式，可以保存之前的分支历史。能够更好的查看 merge 历史，以及 branch 状态</li><li><code>git merge --squash</code>：用来把一些不必要 commit 进行压缩，比如说，你的 feature 在开发的时候写的 commit 很乱，那么我们合并的时候不希望把这些历史 commit 带过来，于是使用 <code>--squash</code> 进行合并，需要进行一次额外的 commit 来“总结”一下，完成最终的合并</li></ul><p>📒 Git 如何变基拉取代码</p><p>在本地 commit 之后，下一步一般会执行 <code>git pull</code> 合并远程分支代码。我们知道 <code>git pull</code> 相当于 <code>git fetch &amp;&amp; git merge</code>，通过 <code>merge</code> 方式合并代码，缺点就是会导致时间线比较混乱，出现大量没用的 commit 记录，给 Code Review 带来不便。另一种方式是变基拉取：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> pull --rebase</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在变基操作的时候，我们不去合并别人的代码，而是直接把我们原先的基础变掉，变成以别人修改过后的新代码为基础，把我们的修改在这个新的基础之上重新进行。变基的好处之一是可以使我们的时间线变得非常干净。</p><p>变基操作的时候，会创建一个临时的 rebasing branch，如有冲突，合并完冲突的文件，添加到暂存区后，执行:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> rebase --continue</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>此时会进入 commit message 编辑界面，输入 <code>:q</code> 就会提交 commit，后续只要推送远程仓库即可。</p><p>如果不想继续变基操作，执行：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> rebase --abort</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Git 操作之 <code>git push -f</code></p><p>在开发一个项目的时候，本人将自己的 <code>feature</code> 分支合并到公共 <code>test</code> 分支，并且在测试环境部署成功。</p><p>几天后再去看的时候，发现测试环境提交的代码都不见了，本人在 <code>test</code> 分支的提交记录也都没了，只有另外一个同事留下的提交记录。最后重新将 <code>feature</code> 分支合到 <code>test</code>，再次部署到测试环境。</p><p>这个事情虽然影响不是很大，毕竟只是部署测试环境的分支，没有影响到 <code>feature</code> 分支，但是后来一直在想，究竟什么操作可以覆盖别人的提交记录。想来想去，应该只有下面几种情况：</p><ul><li><code>git reset</code>：回退版本，实际上就是向后移动 <code>HEAD</code> 指针，该操作不会产生 commit 记录</li><li><code>git revert</code>：撤销某次操作，用一次新的 commit 来回滚之前的 commit，<code>HEAD</code> 继续前进，该操作之前和之后的 commit 和 history 都会保留</li><li><code>git push -f</code>：将自己本地的代码强制推送到远程仓库。当使用 <code>git push</code> 推送报错时，除了耐心解决冲突再提交之外，还可以使用这个命令强制推送，但通常会造成严重后果，例如覆盖别人的提交记录</li></ul><p>由于开发一般都在自己的 <code>feature</code> 分支上，只有在需要测试的时候才会合并 <code>test</code> 分支，因此使用 <code>git reset</code> 可能性不大。<code>git revert</code> 更不可能，不仅不会修改 history，同时还会创建一条新的 commit 记录。因此可能性最大的就是 <code>git push -f</code> 了。</p><p>一般我们推送代码之前都会习惯性执行 <code>git pull</code>，就算不执行 <code>git pull</code>，直接推送，只要有人在你之前推送过也会报错：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> push -u origin main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">error: failed to push some refs to </span><span class="token string" style="color:#e3116c">'https://github.com/Jiacheng787/git-operate-demo.git'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">hint: Updates were rejected because the remote contains work that you </span><span class="token keyword" style="color:#00009f">do</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">hint: not have locally. This is usually caused by another repository pushing</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">hint: to the same ref. You may want to first integrate the remote changes</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">hint: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e.g., </span><span class="token string" style="color:#e3116c">'git pull ...'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> before pushing again.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">hint: See the </span><span class="token string" style="color:#e3116c">'Note about fast-forwards'</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'git push --help'</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> details.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在这种情况下，常规做法是执行 <code>git pull</code> 更新本地提交记录，如有冲突则解决冲突，然后再次推送。另一种做法就是强制推送：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> push -f origin main</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>可以看到就算没有事先 <code>git pull</code> 也不会报错，但是这样会导致远程仓库的提交记录被覆盖，远程仓库的提交记录变成了你本地的记录，你上次同步代码之后别人的提交记录都丢失了。</p><p><strong>如何删除所有 commit 记录</strong></p><p>初始化一个仓库：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> init</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>本地提交：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> </span><span class="token builtin class-name">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> commit -m </span><span class="token string" style="color:#e3116c">"Initial commit"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>下一步强制推送到远程仓库即可：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> branch -m main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> remote </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> origin </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">REPO_TARGET</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> push -f origin main</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Docker 容器如何实现持久化</p><p>Docker 容器本身是无状态的，无法持久化存储，在 Docker 容器中构建前端项目，如何缓存 node_modules 从而提升构建效率？可以给 Docker 容器挂载外部数据卷，映射到本地文件系统，就可以实现持久化存储。</p><p>📒 <a href="https://mp.weixin.qq.com/s/YeOTUw7CiR-rREexcPDHqA" target="_blank" rel="noopener noreferrer">复盘 Node 项目中遇到的13+常见问题和解决方案</a></p><p>📒 GitHub 最受欢迎的Top 20 JavaScript 项目</p><ul><li><a href="https://github.com/yargs/yargs" target="_blank" rel="noopener noreferrer">yargs: 通过使用 Node.js 构建功能全面的命令行应用，它能轻松配置命令，解析多个参数，并设置快捷方式等，还能自动生成帮助菜单</a></li><li><a href="https://github.com/ajv-validator/ajv" target="_blank" rel="noopener noreferrer">Ajv: 一个适用于 Node.js 和浏览器的最快 JSON 验证器</a></li><li><a href="https://github.com/isaacs/yallist" target="_blank" rel="noopener noreferrer">yallist: 一个双向链表的实现</a></li><li><a href="https://github.com/isaacs/rimraf" target="_blank" rel="noopener noreferrer">rimraf: Node.js 的 rm -rf 实用程序。以包的形式包装rm -rf命令，用来删除文件和文件夹，不管文件夹是否为空，都可以删除</a></li></ul><p><a href="https://mp.weixin.qq.com/s/exmChOjKQ1l76LXkuMfzog" target="_blank" rel="noopener noreferrer">GitHub 最受欢迎的Top 20 JavaScript 项目</a></p><p>📒 <a href="https://juejin.cn/post/7081583211427397669" target="_blank" rel="noopener noreferrer">保护自己 - 深入链路探究网络安全</a></p><p>📒 <a href="https://juejin.cn/post/7079447275755274254" target="_blank" rel="noopener noreferrer">50 多个提高前端人效率的工具、网站和书籍整理</a></p><p>📒 <a href="https://juejin.cn/post/7080032725477883917" target="_blank" rel="noopener noreferrer">如何成为一个优秀的复制粘贴工程师</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/14geIwh6BkvaifOIAvz7hw" target="_blank" rel="noopener noreferrer">原创精选荟萃（2022.03.14）</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/g9F05SRnQBTzzfx_2CKqhg" target="_blank" rel="noopener noreferrer">只会用传统开发模式？10分钟教你玩转敏捷！</a></p><p>📒 如何提升 GitHub Page 访问速度</p><p><strong>打包构建</strong></p><p>使用 GitHub Action 作为 CI 环境，使用 Docker 进行构建，充分利用缓存，如 <code>package.json</code> 没变就不重复装包。</p><p><strong>部署</strong></p><p>打包之后将静态资源上传至阿里云 OSS（需要配置 Webpack 的 <code>output.publicPath</code>），提升页面加载速度。</p><p>HTML 页面暂时可以不上传，使用 GitHub Page 托管，这样访问速度可以保证，但是不能解决 GitHub Page 偶尔会挂的问题。还是要将 HTML 页面上传（<code>Cache-Control:no-cache</code>），此时整个网站完全托管在阿里云 OSS 上面，需要域名备案。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>如果页面需要后端服务，也可以不用服务器，直接使用 <strong>云数据库</strong> + <strong>云存储</strong> + <strong>Serverless 云函数</strong>，免去运维成本。</p></div></div><p>📒 Golang 算法</p><blockquote><p><a href="https://github.com/fangbinwei/algorithm-practice" target="_blank" rel="noopener noreferrer">https://github.com/fangbinwei/algorithm-practice</a></p></blockquote><p>📒 Golang 项目参考</p><blockquote><p><a href="https://github.com/fangbinwei/aliyun-oss-website-action" target="_blank" rel="noopener noreferrer">https://github.com/fangbinwei/aliyun-oss-website-action</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/6966857691381645325" target="_blank" rel="noopener noreferrer">你知道的前端优化手段</a></p><p>📒 函数式编程（FP）</p><p>lodash 中的 FP</p><p>在lodash的官网上，我们很容易找到一个 <a href="https://github.com/lodash/lodash/wiki/FP-Guide" target="_blank" rel="noopener noreferrer">function program guide</a> 。在 lodash / fp 模块中提供了实用的对函数式编程友好的方法。里面的方式有以下的特性：</p><ul><li>不可变</li><li>已柯里化（auto-curried）</li><li>迭代前置（iteratee-first）</li><li>数据后置（data-last）</li></ul><p>假如需要将字符串进行如下转换，该如何实现呢？</p><blockquote><p>例如：<code>CAN YOU FEEL MY WORLD</code> -&gt; <code>can-you-feel-my-world</code></p></blockquote><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">_</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'lodash'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> str </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"CAN YOU FEEL MY WORLD"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> split </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">curry</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">sep</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">str</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sep</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> join </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">curry</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">sep</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> arr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sep</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> map </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">curry</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">fn</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> arr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fn</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> f </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">flow</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">' '</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">toLower</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'-'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">f</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 'can-you-feel-my-world'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>我们在使用 lodash 时，做能很多额外的转化动作，那我们试试 fp 模块吧。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">fp</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'lodash/fp'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> str </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"CAN YOU FEEL MY WORLD"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> f </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">flow</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">split</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">' '</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">toLower</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'-'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">f</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 'can-you-feel-my-world'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这种编程方式我们称之为 PointFree，它有 3 个特点：</p><ul><li>不需要指明处理的数据</li><li>只需要合成运算过程</li><li>需要定义一些辅助的基本运算函数</li></ul><blockquote><p>注意：FP 中的 map 方法和 lodash 中的 map 方法参数的个数是不同的，FP 中的 map 方法回调函数只接受一个参数</p></blockquote><p><a href="https://juejin.cn/post/7065093131233919006" target="_blank" rel="noopener noreferrer">函数式编程（FP）</a></p><p>📒 <a href="https://juejin.cn/post/7079995358624874509" target="_blank" rel="noopener noreferrer">一文颠覆大众对闭包的认知</a></p><p>📒 <a href="https://github.com/facebook/react/releases/tag/v18.0.0" target="_blank" rel="noopener noreferrer">React v18 正式版发布</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/P74IVf1lOoT4n5UJNm2Bfg" target="_blank" rel="noopener noreferrer">答好这5个问题，就入门Docker了</a></p><p>📒 手写 Webpack</p><p><a href="https://juejin.cn/post/6854573217336541192" target="_blank" rel="noopener noreferrer">手写webpack核心原理，再也不怕面试官问我webpack原理</a></p><p><a href="https://juejin.cn/post/7077484559893266439" target="_blank" rel="noopener noreferrer">100行代码实现一个组件引用次数统计插件</a></p><p>📒 Golang 指针几点注意</p><ul><li>Golang 中赋值操作、函数参数、函数返回值都是 copy</li><li>基本类型、slice、map 直接传递就行，对于 struct、array 需要特别注意，建议一律传递指针类型</li></ul><p>📒 Dum：Rust 编写的 npm 脚本运行器</p><p>延续了使用不是 JavaScript 来构建 JavaScript 工具的趋势。这个奇怪的名字 “Dum”，旨在取代 <code>npm run</code> 和 <code>npx</code> 来减少任务启动时间的毫秒数。</p><blockquote><p><a href="https://github.com/egoist/dum" target="_blank" rel="noopener noreferrer">https://github.com/egoist/dum</a></p></blockquote><p>📒 Node 之道：关于设计、架构与最佳实践</p><blockquote><p><a href="https://alexkondov.com/tao-of-node/" target="_blank" rel="noopener noreferrer">https://alexkondov.com/tao-of-node/</a></p></blockquote><p>📒 Hooks 的 ”危害性“</p><p>作者声称“每周都能找到十几个与 hooks 相关的问题”，并利用这段经历给出了一些例子和解决方法，以避免“API 的不足之处”。</p><blockquote><p><a href="https://labs.factorialhr.com/posts/hooks-considered-harmful" target="_blank" rel="noopener noreferrer">https://labs.factorialhr.com/posts/hooks-considered-harmful</a></p></blockquote><p>📒 Dockerfile 配置</p><div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"># 两段式构建</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># 第一段构建源码镜像</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ARG PROJECT_DIR=/project</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ARG BB_ENV=prod</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">FROM harbor.hiktest.com/public/vue:2.5-node10 as src</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ARG PROJECT_DIR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ARG BB_ENV</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY . ${PROJECT_DIR}/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WORKDIR ${PROJECT_DIR}/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">RUN npm install &amp;&amp; npm run build:${BB_ENV}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># 第二段从源码镜像中拷贝出编译的dist，做成目标镜像</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">FROM harbor.hiktest.com/hikvision/nginx:1.12</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ARG PROJECT_DIR</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8 TZ=Asia/Shanghai</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime &amp;&amp; echo $TZ &gt; /etc/timezone</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY --from=src ${PROJECT_DIR}/dist /usr/share/nginx/html/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY ./nginx.conf /etc/nginx/nginx.conf</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY ./default.conf /etc/nginx/conf.d/default.conf</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/BIYp9DNd_9sw5O2daiHmlA" target="_blank" rel="noopener noreferrer">万字长文助你上手软件领域驱动设计 DDD</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/6DAyXFHIMW95FS0f3GyHpA" target="_blank" rel="noopener noreferrer">TypeScript 终极初学者指南</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[3月27日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月27日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月27日内容汇总"/>
        <updated>2022-03-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 从 React 源码的类型定义中，我学到了什么？]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7079449083919728671" target="_blank" rel="noopener noreferrer">从 React 源码的类型定义中，我学到了什么？</a></p><p>📒 <a href="https://juejin.cn/post/7079232962025226277" target="_blank" rel="noopener noreferrer">前端单测为什么不要测代码实现细节？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/7LXeQomcHK4zcuRqB32JDg" target="_blank" rel="noopener noreferrer">React+Ts，这样学起来确实简单！！！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/IKmCWwH1LjJ-FrcbbOtj3w" target="_blank" rel="noopener noreferrer">高频 LeetCode 面试题分类</a></p><p>📒 如何在常数时间插入、删除数组中的元素</p><p>之前看到过一个用数组实现队列的方案，移除元素使用 <code>shift</code>，导致时间复杂度为 <code>O(n)</code>，后来改为使用双向链表实现队列，插入删除时间复杂度都为 <code>O(1)</code>。如果使用链表的话，如何在常数时间内查找元素呢，可以使用 <code>Map</code> 存储链表节点指针，从而实现哈希链表的结构。</p><p>话说回来，如果使用数组的方案，如何实现常数时间插入、删除数组元素呢？可以做到！对数组尾部进行插入和删除操作不会涉及数据搬移，时间复杂度是 <code>O(1)</code>。
<strong>所以，如果我们想在 <code>O(1)</code> 的时间删除数组中的某一个元素 <code>val</code>，可以先把这个元素交换到数组的尾部，然后再 <code>pop</code> 掉</strong>。</p><p>📒 <a href="https://github.com/alexmacarthur/typeit" target="_blank" rel="noopener noreferrer">Typeit：轻量级代码录制回放</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/byD6xm3O6MzX8kksjBmqpA" target="_blank" rel="noopener noreferrer">React 18 超全升级指南</a></p><p>📒 <a href="https://juejin.cn/post/7077122129107353636" target="_blank" rel="noopener noreferrer">「多图详解」NodeJs中EventLoop与浏览器下的差异性</a></p><p>📒 <a href="https://juejin.cn/post/7077814044152823838" target="_blank" rel="noopener noreferrer">超爽！VSCode 实现自动原子化 CSS 样式</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/f581rfvKWE3KGgWfZDJ2cA" target="_blank" rel="noopener noreferrer">云计算时代，你还不会 Docker ？ 一万字总结（建议收藏）</a></p><p>📒 腾讯云后端15连问</p><p>三数之和，可以先对数组进行排序，然后使用左右指针</p><p><a href="https://mp.weixin.qq.com/s/aMYJODhtWsBt9CTJxySQEQ" target="_blank" rel="noopener noreferrer">腾讯云后端15连问！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/dg4WI2eJzh6b3OAzHN0q3A" target="_blank" rel="noopener noreferrer">十道腾讯算法真题解析！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/66sos7nML5rA0ZZGJ5qFIQ" target="_blank" rel="noopener noreferrer">[<!-- -->科普文<!-- -->]<!-- --> Vue3 到底更新了什么？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/mz5S1iiRWkk-KKJg5lOOJQ" target="_blank" rel="noopener noreferrer">基于 TypeScript 理解程序设计的 SOLID 原则</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/usMxG3cAowUtO3Lvn9VjsQ" target="_blank" rel="noopener noreferrer">晋升，如何减少 50%+ 的答辩材料准备时间、调整心态（个人经验总结）</a></p><p>📒 <a href="https://www.bilibili.com/video/BV1bZ4y167gz" target="_blank" rel="noopener noreferrer">【Anthony Fu】写个聪明的打字机！直播录像</a></p><p>📒 <a href="https://github.com/unjs" target="_blank" rel="noopener noreferrer">https://github.com/unjs</a></p><p>📒 如何理解 partition 函数</p><p>利用左右指针，其实有点类似反转数组，只不过反转数组对每个元素都交换一下，而 partition 只有在特定条件下进行交换：</p><ul><li>左指针向右移动，直到 <code>nums[i] &gt; pivot</code> 停止移动，此时再移动右指针，接下来会有两种情况<ul><li>右指针遇到 <code>nums[j] &lt;= pivot</code> 时停止移动，此时进行元素交换</li><li>左指针右侧的元素都大于 <code>pivot</code>，没有元素需要交换，最终两个指针重合，停止操作</li></ul></li><li>不断重复上述步骤，直到交换结束，此时 <code>nums[j]</code> 为较小值，将 <code>pivot</code> 与 <code>nums[j]</code> 交换</li></ul><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">partition</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hi</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> pivot </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">lo</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> lo </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    j </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> hi </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> pivot</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">j </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> lo </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> pivot</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      j</span><span class="token operator" style="color:#393A34">--</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> j</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">swap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> j</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">swap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> j</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> j</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">swap</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> j</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> temp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/7071518211392405541" target="_blank" rel="noopener noreferrer">在项目中用ts封装axios，一次封装整个团队受益😁</a></p><p>📒 阿里三面：灵魂拷问——有react fiber，为什么不需要vue fiber呢</p><p>为什么递归遍历 vdom 树不能中断</p><p>这种遍历有一个特点，必须一次性完成。假设遍历发生了中断，虽然可以保留当下进行中节点的索引，下次继续时，我们的确可以继续遍历该节点下面的所有子节点，但是没有办法找到其父节点——因为每个节点只有其子节点的指向。断点没有办法恢复，只能从头再来一遍。</p><p>在新的架构中，每个节点有三个指针：分别指向第一个子节点、下一个兄弟节点、父节点。这种数据结构就是fiber，它的遍历规则如下：</p><ol><li>从根节点开始，依次遍历该节点的子节点、兄弟节点，如果两者都遍历了，则回到它的父节点；</li><li>当一个节点的所有子节点遍历完成，才认为该节点遍历完成；</li></ol><p>提出问题：render 阶段 vdom 转 fiber 还是通过递归的方式，那么 fiber 链表可中断遍历是在哪一步</p><p><a href="https://juejin.cn/post/7077545184807878692" target="_blank" rel="noopener noreferrer">阿里三面：灵魂拷问——有react fiber，为什么不需要vue fiber呢</a></p><p><a href="https://react.iamkasong.com/process/reconciler.html" target="_blank" rel="noopener noreferrer">React 技术揭秘</a></p><p>📒 <a href="https://juejin.cn/post/7064864648729722887" target="_blank" rel="noopener noreferrer">Vue组件库设计 | Vue3组件在线交互解释器</a></p><p>📒 React 类组件注意事项</p><p><strong>1. 为了避免组件不必要的 rerender，建议继承 <code>PureComponent</code></strong></p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyCompoment</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">PureComponent</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><code>PureComponent</code> 相当于函数组件使用 <code>React.memo</code></p></blockquote><p><strong>2. 在构造方法中如要使用 <code>this</code>，则必须先调用 <code>super()</code></strong></p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyCompoment</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Component</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 如果想在构造方法中使用 this，则必须先调用 super()</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// super 实际上就是父类构造方法，类似盗用构造函数继承</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 下面是一个声明 state 的例子</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如果使用 ES2022 Class Properties 语法，则可以直接干掉构造方法，更加简洁：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyCompoment</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Component</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 使用 ES2022 Class Properties 语法</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>3. 状态更新可能是异步的</strong></p><p>React 可能会对多次 <code>setState()</code> 调用进行批处理，使组件只更新一次，因此 <code>this.props</code> 和 <code>this.state</code> 可能会异步更新。所以不能依赖 <code>this.state</code> 计算下一个状态，这种情况下，可以使用函数式更新：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">setState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">prevState</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> prevProps</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">counter</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> prevState</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">counter</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> prevProps</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">increment</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>4 类组件中需要注意事件处理函数的 <code>this</code> 绑定问题</strong></p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyCompoment</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Component</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">handleClick</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">handleClick</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">handleClick</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'===点击事件'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript keyword" style="color:#00009f">this</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">handleClick</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">点击</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如果使用 ES2022 Class Properties 语法，也可以让语法更简洁：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyCompoment</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Component</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">handleClick</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'===点击事件'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript keyword" style="color:#00009f">this</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">handleClick</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">点击</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 箭头函数两个注意点</p><details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>查看详情</summary><div><div class="collapsibleContent_i85q"><p><strong>1. 箭头函数中 <code>this</code> 指向能否改变</strong></p><p>以下引用阮一峰 ES6 教程：</p><blockquote><p>箭头函数没有自己的 <code>this</code> 对象，内部的 <code>this</code> 就是定义时上层作用域中的 <code>this</code>。也就是说，箭头函数内部的 <code>this</code> 指向是固定的，相比之下，普通函数的 <code>this</code> 指向是可变的</p></blockquote><p>看了上面这段描述，很多同学可能都认为，箭头函数的 <code>this</code> 是无法改变的，但实际上箭头函数的 <code>this</code> 是跟着上层作用域走的，只要上层作用域的 <code>this</code> 改变，箭头函数中的 <code>this</code> 也会相应改变：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">bar</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 箭头函数的 this 来自 foo 函数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">bar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> o1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2333"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> o2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"666"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">o1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 2333</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">o2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 666</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如果将上述代码编译为 ES5 就能很容易理解上述过程：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> _this </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">bar</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">bar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>2. 为什么“类方法”可以使用箭头函数</strong></p><p>在博客中看到有这样的代码：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">getName</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>咋一看好像没有问题，但是仔细一想发现不对，原型对象在所有实例之间是共享的，因此类方法的 <code>this</code> 必须要动态绑定，而箭头函数的 <code>this</code> 是静态的，这样不就有 bug 了，但是试验发现并没有问题：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> p1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"2333"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 2333</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> p2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"666"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 666</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这是因为，<code>getName</code> 实际并不是类方法，而是 ES2022 中类属性的写法，<code>getName</code> 实际上是一个对象的自有属性，可以使用下面的代码证明：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">prototype</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">hasOwnProperty</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"getName"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// true</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这一点在 React 文档事件处理函数 <code>this</code> 绑定中也有说明：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Foo</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">Component</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Note: this syntax is experimental and not standardized yet.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">handleClick</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Click happened'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript keyword" style="color:#00009f">this</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">handleClick</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">Click Me</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://reactjs.org/docs/faq-functions.html#how-do-i-bind-a-function-to-a-component-instance" target="_blank" rel="noopener noreferrer">https://reactjs.org/docs/faq-functions.html#how-do-i-bind-a-function-to-a-component-instance</a></p></blockquote><p>而类方法有且仅有下面这种写法：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">getName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>使用箭头函数作为类属性时，绑定 <code>this</code> 的过程如下：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">getName</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> o </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token maybe-class-name">Person</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">bind</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"2333"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 2333</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>在 <code>new</code> 调用过程中，<code>Person</code> 函数的 <code>this</code> 会绑定到实例对象上，箭头函数的 <code>this</code> 就是 <code>Person</code> 函数的 <code>this</code>，因此箭头函数的 <code>this</code> 会指向实例对象，并且由于箭头函数作为类的自有属性，会在每次 <code>new</code> 的时候重新生成，因此不同实例之间不会影响</p></blockquote></div></div></details><p>📒 <a href="https://zhuanlan.zhihu.com/p/476712416" target="_blank" rel="noopener noreferrer">我的第一次webpack优化，首屏渲染从9s到1s</a></p><p>📒 <a href="https://juejin.cn/post/7077536309804859428" target="_blank" rel="noopener noreferrer">几个一看就会的 TypeScript 小技巧</a></p><p>📒 <a href="https://nextjs.org/learn/foundations/about-nextjs" target="_blank" rel="noopener noreferrer">Next.js 官方发布全新教程</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[3月20日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月20日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月20日内容汇总"/>
        <updated>2022-03-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 以 pnpm 为例谈谈如何调试大型项目]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7075584391522713613" target="_blank" rel="noopener noreferrer">以 pnpm 为例谈谈如何调试大型项目</a></p><p>📒 如何实现双向链表</p><details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>查看详情</summary><div><div class="collapsibleContent_i85q"><p>  在项目中遇到一个问题，源码中使用数组模拟队列，添加使用 <code>unshift</code>，移除使用 <code>pop</code>，导致添加元素的时间复杂度为 <code>O(n)</code>。这里使用双向链表模拟队列，两端均可添加、删除元素，且时间复杂度均为 <code>O(1)</code>：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 链表节点</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ListNode</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> next</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ListNode</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> prev</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ListNode</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 实现双向链表</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">LinkedList</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> head</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ListNode</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> end</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ListNode</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> _size</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * add() 相当于 addLast()</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @param val </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @returns </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ListNode</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 初始化 head 指针</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 初始化 end 指针</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 把新节点挂到链表最后</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 新节点 prev 指向前一节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">prev </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// end 指针后移一位</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 维护 size</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_size</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * addFirst() 在链表头部添加</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @param val </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @returns </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">addFirst</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ListNode</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 初始化 head 指针</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 把新节点挂到链表头部</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">prev </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 新节点 next 指向下一节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// head 指针前移一位</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 初始化 end 指针</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 维护 size</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_size</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * poll() 相当于 pollFirst()</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @returns </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">poll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 缓存需要删除的节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// head 指向下一节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 切断与前一节点的联系</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">prev </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 维护 size</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_size</span><span class="token operator" style="color:#393A34">--</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * pollLast() 移除链表尾部元素</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @returns </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">pollLast</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 缓存需要删除的节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// end 指向前一节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">prev</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 切断与后一节点的联系</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 维护 size</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_size</span><span class="token operator" style="color:#393A34">--</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * 获取链表长度</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @returns </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_size</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * 序列化为字符串</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   * @returns </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">   */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> res</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> list </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">list </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">list</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      list </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> list</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">[ </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">res</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation function" style="color:#d73a49">join</span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation string" style="color:#e3116c">" "</span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c"> ]</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details><p>📒 <a href="https://juejin.cn/post/7076431946834214925" target="_blank" rel="noopener noreferrer">Nest.js 的 AOP 架构的好处，你感受到了么？</a></p><p>📒 React Hooks 源码分析</p><p>React 函数组件通过 <code>renderWithHooks</code> 函数进行渲染，里面有个 <code>workingInProgress</code> 的对象就是当前的 fiber 节点，fiber 节点的 <code>memorizedState</code> 就是保存 hooks 数据的地方。它是一个通过 <code>next</code> 串联的链表。</p><p>这个 <code>memorizedState</code> 链表是什么时候创建的呢？确实有个链表创建的过程，也就是 mountXxx。链表只需要创建一次，后面只需要 update。所以第一次调用 <code>useState</code> 会执行 <code>mountState</code>，后面再调用 <code>useState</code> 会执行 <code>updateState</code>。</p><p>每个 Hook 的 <code>memorizedState</code> 链表节点是通过 <code>mountWorkInProgressHook</code> 函数创建的：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">mountWorkInProgressHook</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Hook</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> hook </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">memoizedState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">baseState</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">baseQueue</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">queue</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">next</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">workInProgressHook </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// This is the first hook in the list</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    currentlyRenderingFiber</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">memoizedState</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> workInProgressHook </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> hook</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Append to the end of the list</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    workInProgressHook </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> workInProgressHook</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">next</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> hook</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> workInProgressHook</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>函数组件本身是没有挂载、更新的概念的，每次 rerender 就是执行这个函数，但是挂载、更新的逻辑体现在 Hooks 里面，首次执行的时候调用 <code>mountWorkInProgressHook</code> 创建链表节点，后续执行的时候调用 <code>updateWorkInProgressHook</code> 访问并更新链表节点</p></blockquote><p><a href="https://juejin.cn/post/7075701341997236261" target="_blank" rel="noopener noreferrer">React Hooks 的原理，有的简单有的不简单</a></p><p><a href="https://juejin.cn/book/6945998773818490884/section/6959872072906440743" target="_blank" rel="noopener noreferrer">React 进阶实战指南 - 原理篇：Hooks 原理</a></p><p>📒 前端工程师如何快速使用一个NLP模型</p><p>2017年谷歌提出了Transformer架构模型，2018年底，基于Transformer架构，谷歌推出了bert模型，bert模型一诞生，便在各大11项NLP基础任务中展现出了卓越的性能，现在很多模型都是基于或参考Bert模型进行改造。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>如果想了解 Transformer 和 bert，可以看这个视频</p><p><a href="https://www.bilibili.com/video/BV1P4411F77q" target="_blank" rel="noopener noreferrer">https://www.bilibili.com/video/BV1P4411F77q</a></p><p><a href="https://www.bilibili.com/video/BV1Mt411J734" target="_blank" rel="noopener noreferrer">https://www.bilibili.com/video/BV1Mt411J734</a></p></div></div><p><a href="https://juejin.cn/post/7075518863814869005" target="_blank" rel="noopener noreferrer">前端工程师如何快速使用一个NLP模型</a></p><p>📒 <a href="https://juejin.cn/post/7075493514510860318" target="_blank" rel="noopener noreferrer">Lerna 运行流程剖析</a></p><p>⭐️ <a href="https://juejin.cn/post/7071780876501123085" target="_blank" rel="noopener noreferrer">Git不要只会pull和push，试试这5条提高效率的命令</a></p><p>📒 <a href="https://juejin.cn/post/7073692220313829407" target="_blank" rel="noopener noreferrer">React内部的性能优化没有达到极致？</a></p><p>📒 reduce 方法注意事项</p><table><thead><tr><th></th><th>初始值非空</th><th>初始值为空</th></tr></thead><tbody><tr><td>数组非空</td><td>首次执行回调，accu 为初始值，cur 为数组第一项</td><td>首次执行回调，accu 为数组第一项，cur 为数组第二项</td></tr><tr><td>数组为空</td><td>不执行回调，直接返回初始值</td><td>报错（建议任何情况下都传递初始值）</td></tr></tbody></table><p>📒 npm 安装依赖默认添加 <code>^</code> 前缀，当再次执行 npm install 命令时，会自动安装这个包在此大版本下的最新版本。如果想要修改这个功能，可以执行以下命令：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> config </span><span class="token builtin class-name">set</span><span class="token plain"> save-prefix</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'~'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>执行完该命令之后，就会把 <code>^</code> 符号改为 <code>~</code> 符号。当再次安装新模块时，就从只允许小版本的升级变成了只允许补丁包的升级</p></blockquote><p>如果想要锁定当前的版本，可以执行以下命令：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> config </span><span class="token builtin class-name">set</span><span class="token plain"> save-exact </span><span class="token boolean" style="color:#36acaa">true</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>这样每次 <code>npm install xxx --save</code> 时就会锁定依赖的版本号，相当于加了 <code>--save-exact</code> 参数。建议线上的应用都采用这种锁定版本号的方式</p></blockquote><p>既然可以锁定依赖版本，为什么还需要 lcok-file 呢，个人理解锁定依赖只能锁定当前项目中的依赖版本，但是还存在间接依赖，即依赖还有依赖，直接锁定依赖版本无法解决间接依赖的问题，间接依赖版本还是不受控制，需要借助 lock-file 锁定间接依赖的版本。</p><p>📒 函数式编程三种形式：</p><ul><li>函数赋值给变量<ul><li>可作为数组的元素，进而实现 compose 函数组合，或者管道操作</li></ul></li><li>函数作为参数<ul><li>常见的有 <code>forEach</code> 、<code>Promise</code> 、<code>setTimeout</code> 等，React 技术栈也有很多 API</li></ul></li><li>函数作为返回值</li></ul><p>📒 <a href="https://juejin.cn/post/7074780794459258917" target="_blank" rel="noopener noreferrer">GitLab CI 打造一条自己的流水线</a></p><p>📒 type-challenges</p><p>type-challenges 是一个 TypeScript 类型体操姿势合集。本项目意在于让你更好的了解 TS 的类型系统，编写你自己的类型工具，或者只是单纯的享受挑战的乐趣！</p><blockquote><p><a href="https://github.com/type-challenges/type-challenges" target="_blank" rel="noopener noreferrer">https://github.com/type-challenges/type-challenges</a></p></blockquote>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[3月13日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月13日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月13日内容汇总"/>
        <updated>2022-03-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 React 18 RC 版本发布啦，生产环境用起来！]]></summary>
        <content type="html"><![CDATA[<p>📒 React 18 RC 版本发布啦，生产环境用起来！</p><p>安装最新的 React 18 RC 版本（Release Candidate候选版本）：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">yarn</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> react@rc react-dom@rc</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>注意在 React 18 中新增了 <code>concurrent Mode</code> 模式，通过新增的 <code>createRoot</code> API 开启：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">ReactDOM</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-dom'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 通过 createRoot 创建 root</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> root </span><span class="token operator" style="color:#393A34">=</span><span class="token plain">  </span><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createRoot</span><span class="token punctuation" style="color:#393A34">(</span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getElementById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'app'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 调用 root 的 render 方法</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">App</span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><code>startTransition</code> 特性依赖 <code>concurrent Mode</code> 模式运行</p></blockquote><p>如果使用传统 legacy 模式，会按 React 17 的方式运行：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">ReactDOM</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'react-dom'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 通过 ReactDOM.render</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">App</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getElementById</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'app'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>React 18 主要是对自动批处理进行优化。在 React 18 之前实际上已经有批处理机制，但是只针对同步代码，如果放在 <code>Promise</code>、<code>setTimeout</code> 等异步回调中，自动批处理会失效。</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Example</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">React</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Component</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">componentDidMount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 自动批处理更新</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 注意此时 setState 是异步的</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">setState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token literal-property property" style="color:#36acaa">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">setState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token literal-property property" style="color:#36acaa">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 自动批处理失效</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 此时 setState 是同步的</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">setState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token literal-property property" style="color:#36acaa">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">setState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token literal-property property" style="color:#36acaa">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在 React 18 版本之前，上面代码的打印顺序是 0、0、2、3</p><p>React 18 版本解决了这个问题，在异步回调中更新状态也能触发自动批处理，打印的顺序是 0、0、1、1</p><p>总结一下主要有以下几个新特性：</p><ul><li>新的 <code>ReactDOM.createRoot()</code> API（替换 <code>ReactDOM.render()</code>）</li><li>新的 <code>startTransition</code> API（用于非紧急状态更新）</li><li>渲染的自动批处理优化（主要解决异步回调中无法批处理的问题）</li><li>支持 <code>React.lazy</code> 的 全新 SSR 架构（支持 <code>&lt;Suspense&gt;</code> 组件）</li></ul><p><a href="https://mp.weixin.qq.com/s/pXlouBy7JcH8ImtQ6e-FCA" target="_blank" rel="noopener noreferrer">React 18 RC 版本发布啦，生产环境用起来！</a></p><p>📒 <a href="https://juejin.cn/post/7040792659153125413" target="_blank" rel="noopener noreferrer">CSS TreeShaking 原理揭秘： 手写一个 PurgeCss</a></p><p>📒 <a href="https://juejin.cn/user/1425383933618990" target="_blank" rel="noopener noreferrer">「源码解析」一文吃透react-redux源码（useMemo经典源码级案例）</a></p><p>📒 <a href="https://zhuanlan.zhihu.com/p/473970384" target="_blank" rel="noopener noreferrer">Recoil实现原理浅析-异步请求</a></p><p>📒 WebSocket 基础与应用系列（一）—— 抓个 WebSocket 的包</p><p>HTTP 和 WebSocket 都属于应用层协议，都是基于 TCP 来传输数据的，可以理解为对 TCP 的封装，都要遵循 TCP 的三次握手和四次挥手，只是在连接之后发送的内容（报文格式）不同，或者是断开的时间不同。</p><p>如何使用 Wireshark 抓包：</p><ul><li>在 Capture 中选择本机回环网络</li><li>在 filter 中写入过滤条件 tcp.port == 3000</li></ul><p><a href="https://mp.weixin.qq.com/s/f96Da8kCluNwv7cxW39gzg" target="_blank" rel="noopener noreferrer">WebSocket 基础与应用系列（一）—— 抓个 WebSocket 的包</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/_g9NZnSBjGFmLaU0Y6u9aA" target="_blank" rel="noopener noreferrer">CSS 代码优化的12个小技巧</a></p><p>📒 <a href="https://juejin.cn/post/7073424271904768014" target="_blank" rel="noopener noreferrer">JS 框架解决了什么问题</a></p><p>📒 <a href="https://segmentfault.com/a/1190000041112360" target="_blank" rel="noopener noreferrer">反向操作，用 Object.defineProperty 重写 @vue/reactivity</a></p><p>📒 antfu 大佬的 eslint 配置</p><blockquote><p><a href="https://github.com/antfu/eslint-config" target="_blank" rel="noopener noreferrer">https://github.com/antfu/eslint-config</a></p></blockquote><p>📒 antfu 大佬的 vscode 配置</p><blockquote><p><a href="https://github.com/antfu/vscode-settings" target="_blank" rel="noopener noreferrer">https://github.com/antfu/vscode-settings</a></p></blockquote><p>📒 使用 tsdoc 编写规范的注释</p><blockquote><p><a href="https://tsdoc.org/" target="_blank" rel="noopener noreferrer">https://tsdoc.org/</a></p></blockquote><p>📒 npm 包发布工具</p><blockquote><p><a href="https://github.com/JS-DevTools/version-bump-prompt" target="_blank" rel="noopener noreferrer">https://github.com/JS-DevTools/version-bump-prompt</a></p></blockquote><p>📒 使用 pnpm 作为包管理工具</p><p>基本用法：</p><ul><li><code>pnpm add &lt;pkg&gt;</code>：安装依赖</li><li><code>pnpm add -D &lt;pkg&gt;</code>：安装依赖到 devDependencies</li><li><code>pnpm install</code>：安装所有依赖</li><li><code>pnpm -r update</code>：递归更新每个包的依赖</li><li><code>pnpm -r update typescript@latest</code>：将每个包的 typescript 更新为最新版本</li><li><code>pnpm remove</code>：移除依赖</li></ul><p>如何支持 monorepo 项目：<a href="https://pnpm.io/zh/workspaces" target="_blank" rel="noopener noreferrer">https://pnpm.io/zh/workspaces</a></p><p><code>pnpm -r</code> 带一个参数 <code>-r</code> 表示进行递归操作。</p><p><a href="https://pnpm.io/zh/" target="_blank" rel="noopener noreferrer">pnpm 官方文档</a></p><p><a href="https://juejin.cn/post/7038192011882528776" target="_blank" rel="noopener noreferrer">为什么 vue 源码以及生态仓库要迁移 pnpm?</a></p><p>📒 推荐两个打包工具</p><ul><li><a href="https://github.com/egoist/tsup" target="_blank" rel="noopener noreferrer">tsup</a></li><li><a href="https://github.com/unjs/unbuild" target="_blank" rel="noopener noreferrer">unbuild</a></li></ul><p>📒 seedrandom：JS 种子随机数生成器</p><p>种子随机数生成器，生成是随机的，但是每次调用生成的值是固定的：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> seedrandom </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'seedrandom'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> rng </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">seedrandom</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'hello.'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">rng</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 第一次调用总是 0.9282578795792454</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">rng</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 第二次调用总是 0.3752569768646784</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://github.com/davidbau/seedrandom" target="_blank" rel="noopener noreferrer">https://github.com/davidbau/seedrandom</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/6866973719634542606" target="_blank" rel="noopener noreferrer">深入Node.js的模块加载机制，手写require函数</a></p><p>📒 <a href="https://juejin.cn/post/6949385808755294245" target="_blank" rel="noopener noreferrer">require加载器实现原理</a></p><p>📒 <a href="https://juejin.cn/post/6844903942074138637" target="_blank" rel="noopener noreferrer">聊一聊前端算法面试——递归</a></p><p>📒 <a href="https://juejin.cn/post/7073286650364690439" target="_blank" rel="noopener noreferrer">589. N 叉树的前序遍历 :「递归」&amp;「非递归」&amp;「通用非递归」</a></p><p>📒 Million v1.5：一种快速虚拟 DOM 的实现</p><p>专注于性能和大小，压缩后小于 1KB，如果您想要一个抽象的 VDOM 实现，Million 是你构建自己的框架或库时理想的选择</p><blockquote><p><a href="https://millionjs.org/" target="_blank" rel="noopener noreferrer">https://millionjs.org/</a></p></blockquote><p>📒 200 行代码使用 React 实现俄罗斯方块</p><blockquote><p><a href="https://blog.ag-grid.com/tetris-to-learn-react/" target="_blank" rel="noopener noreferrer">https://blog.ag-grid.com/tetris-to-learn-react/</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7073070819219505166" target="_blank" rel="noopener noreferrer">真实案例说明 TypeScript 类型体操的意义</a></p><p>📒 <a href="https://juejin.cn/post/7007214462813863950" target="_blank" rel="noopener noreferrer">「React 进阶」 学好这些 React 设计模式，能让你的 React 项目飞起来🛫️</a></p><p>📒 <a href="https://juejin.cn/post/7068081327857205261" target="_blank" rel="noopener noreferrer">「1.9W字总结」一份通俗易懂的 TS 教程，入门 + 实战！</a></p><p>📒 Oclif v2.5：Heroku 开源的 CLI 框架</p><p>一个用于构建 CLI 脚手架的成熟框架，无论是简单的参数解析还是很多功能指令都可以驾驭。</p><blockquote><p><a href="https://github.com/oclif/oclif" target="_blank" rel="noopener noreferrer">https://github.com/oclif/oclif</a></p></blockquote><p>📒 使用 Rust 与 WebAssembly 重新实现了 Node 的 URL 解析器</p><blockquote><p><a href="https://www.yagiz.co/implementing-node-js-url-parser-in-webassembly-with-rust/" target="_blank" rel="noopener noreferrer">https://www.yagiz.co/implementing-node-js-url-parser-in-webassembly-with-rust/</a></p></blockquote><p>📒 PDF：从 JavaScript 到 Rust：新书免费发布</p><blockquote><p><a href="https://github.com/vinodotdev/node-to-rust/releases/download/v1/from-javascript-to-rust.pdf" target="_blank" rel="noopener noreferrer">https://github.com/vinodotdev/node-to-rust/releases/download/v1/from-javascript-to-rust.pdf</a></p></blockquote><p>📒 Red Hat 和 IBM 团队的 Node.js “架构参考”</p><blockquote><p><a href="https://github.com/nodeshift/nodejs-reference-architecture" target="_blank" rel="noopener noreferrer">https://github.com/nodeshift/nodejs-reference-architecture</a></p></blockquote><p>📒 在 Node 环境下使用 <code>execa</code> 运行命令</p><blockquote><p><a href="https://blog.logrocket.com/running-commands-with-execa-in-node-js/" target="_blank" rel="noopener noreferrer">https://blog.logrocket.com/running-commands-with-execa-in-node-js/</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7069315908597973023" target="_blank" rel="noopener noreferrer">万字长文详解从零搭建企业级 vue3 + vite2+ ts4 框架全过程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KIXV81MGIpkJUBIsBkqrgA" target="_blank" rel="noopener noreferrer">从 Linux 源码的角度解释进程</a></p><p>📒 10 React Antipatterns to Avoid - Code This, Not That!</p><blockquote><p><a href="https://www.youtube.com/watch?v=b0IZo2Aho9Y" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=b0IZo2Aho9Y</a></p></blockquote><p>📒 markdown 编辑器滚动如何实现联动</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">ScrollTarget</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">NONE</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"NONE"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">EDITOR</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"EDITOR"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token constant" style="color:#36acaa">RENDER</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"RENDER"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> curTarget </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">ScrollTarget</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NONE</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> timer </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">scrollManager</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">handler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">curTarget </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">ScrollTarget</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NONE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    curTarget </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">curTarget </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">handler</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">timer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">clearTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">timer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    timer </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      curTarget </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">ScrollTarget</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NONE</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> scrollFn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">scrollManager</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">handleScroll</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Webpack 的模块规范</p><p>Webpack 基于 CJS 和 ESM 规范实现了模块机制，但也不是完全基于，而是在这些模块规范基础上扩展了一套自己的 api，用于增强功能，例如：</p><ul><li><code>require.context</code></li><li>使用 <code>import</code> 加载 <code>.json</code> 模块</li></ul><blockquote><p>在 ESM 规范中 <code>import</code> 只能用于加载 JS 模块，只有 <code>require</code> 可以加载 json 模块</p></blockquote><p>📒 如何将对象序列化为查询字符串</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> aaa </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token literal-property property" style="color:#36acaa">a</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">b</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">c</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2333"</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>第一种手动拼接，简单直接，一行代码搞定：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">_stringify</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">obj</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">entries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">obj</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">[</span><span class="token parameter">key</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> val</span><span class="token parameter punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">key</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">=</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">val</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"&amp;"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>还可以使用 <code>URLSearchParams</code> 对象进行拼接：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">_stringify</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token parameter">obj</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">entries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">obj</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">accu</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> </span><span class="token parameter punctuation" style="color:#393A34">[</span><span class="token parameter">key</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> val</span><span class="token parameter punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  accu</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> accu</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">URLSearchParams</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 「深入浅出」主流前端框架更新批处理方式</p><p>浏览器环境下，宏任务的执行并不会影响到浏览器的渲染和响应，即宏任务优先级低于页面渲染。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'----宏任务执行----'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 通过递归调用 run 函数，让 setTimeout 宏任务反复执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这种情况下 setTimeout 执行并不影响页面渲染和交互事件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>微任务会在当前 event loop 中执行完毕，会阻塞浏览器的渲染和响应，即微任务优先级高于页面渲染。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token known-class-name class-name">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 在这种情况下，页面直接卡死了，没有响应</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这里主要就是理解关键渲染路径，即浏览器渲染一帧会先执行脚本，再页面布局，绘制渲染。如果是宏任务，浏览器会把每一次事件回调放在下一帧渲染前执行，这样可以确保浏览器每一帧都能正常渲染。如果是微任务，浏览器在执行渲染之前会清空微任务队列，会导致一直停留在当前 event loop，相当于脚本一直在执行，如果长时间不把控制权交还给浏览器，就会影响下一帧的渲染，导致页面出现卡顿和事件响应不及时。</p><p><a href="https://juejin.cn/post/7072156913789566989" target="_blank" rel="noopener noreferrer">「深入浅出」主流前端框架更新批处理方式</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[3月6日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月6日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/3月6日内容汇总"/>
        <updated>2022-03-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 通过Vue自定义指令实现前端埋点]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://mp.weixin.qq.com/s/baVNEeZZdmqUiolyssZgqg" target="_blank" rel="noopener noreferrer">通过Vue自定义指令实现前端埋点</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/qnA1tFKMXr7hwsEKFXKOZg" target="_blank" rel="noopener noreferrer">Deno 简介：它比 Node.js 更好吗？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/2leA0q8QQvdQzv86ic7ZEg" target="_blank" rel="noopener noreferrer">快来玩转这 19 个 css 技巧</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/l3l9d9sLiWoUM381E9o-3Q" target="_blank" rel="noopener noreferrer">解决了 Redis 大 key 问题，同事们都说牛皮！</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/l_YdpyHht5Ayvrc7LFZNIA" target="_blank" rel="noopener noreferrer">图解|Linux内存背后的那些神秘往事</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/36CqC1U54LUd4-izt4iZ1g" target="_blank" rel="noopener noreferrer">深入理解Go Json.Unmarshal精度丢失之谜</a></p><p>📒 如何理解快速排序和归并排序</p><p>快速排序实际就是二叉树的前序遍历，归并排序实际就是二叉树的后序遍历。</p><p>快速排序的逻辑是，若要对 <code>nums[lo..hi]</code> 进行排序，我们先找一个分界点 <code>p</code>，通过交换元素使得 <code>nums[lo..p-1]</code> 都小于等于 <code>nums[p]</code>，且 <code>nums[p+1..hi]</code> 都大于 <code>nums[p]</code>，然后递归地去 <code>nums[lo..p-1]</code> 和 <code>nums[p+1..hi]</code> 中寻找新的分界点，最后整个数组就被排序了。</p><p>快速排序的代码框架如下：</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/****** 前序遍历位置 ******/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 通过交换元素构建分界点 p</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> p </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">partition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/************************/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> p </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> p </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>先构造分界点，然后去左右子数组构造分界点，你看这不就是一个二叉树的前序遍历吗</p></blockquote><p>再说说归并排序的逻辑，若要对 <code>nums[lo..hi]</code> 进行排序，我们先对 <code>nums[lo..mid]</code> 排序，再对 <code>nums[mid+1..hi]</code> 排序，最后把这两个有序的子数组合并，整个数组就排好序了。</p><p>归并排序的代码框架如下：</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lo </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 排序 nums[lo..mid]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mid</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 排序 nums[mid+1..hi]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/****** 后序位置 ******/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 合并 nums[lo..mid] 和 nums[mid+1..hi]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">merge</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mid</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/*********************/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>先对左右子数组排序，然后合并（类似合并有序链表的逻辑），你看这是不是二叉树的后序遍历框架？另外，这不就是传说中的分治算法嘛，不过如此呀</p></blockquote><p>说了这么多，旨在说明，二叉树的算法思想的运用广泛，甚至可以说，只要涉及递归，都可以抽象成二叉树的问题。</p><p>📒 Leetcode 236 二叉树最近公共祖先</p><p><code>lowestCommonAncestor</code> 方法的定义：给该函数输入三个参数 <code>root</code>，<code>p</code>，<code>q</code>，它会返回一个节点。</p><ul><li>情况 1，如果 <code>p</code> 和 <code>q</code> 都在以 <code>root</code> 为根的树中，函数返回的即 <code>p</code> 和 <code>q</code> 的最近公共祖先节点。</li><li>情况 2，如果 <code>p</code> 和 <code>q</code> 都不在以 <code>root</code> 为根的树中，则理所当然地返回 <code>null</code> 呗。</li><li>情况 3，如果 <code>p</code> 和 <code>q</code> 只有一个存在于 <code>root</code> 为根的树中，函数就返回那个节点。</li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>题目说了输入的 <code>p</code> 和 <code>q</code> 一定存在于以 <code>root</code> 为根的树中，但是递归过程中，以上三种情况都有可能发生，所以说这里要定义清楚，后续这些定义都会在代码中体现。</p><p>函数参数中的变量是 <code>root</code>，因为根据框架，<code>lowestCommonAncestor(root)</code> 会递归调用 <code>root.left</code> 和 <code>root.right</code>；至于 <code>p</code> 和 <code>q</code>，我们要求它俩的公共祖先，它俩肯定不会变化的。你也可以理解这是「状态转移」，每次递归在做什么？不就是在把「以root为根」转移成「以root的子节点为根」，不断缩小问题规模嘛</p></div></div><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Solution</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">TreeNode</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">lowestCommonAncestor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TreeNode</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">TreeNode</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">TreeNode</span><span class="token plain"> q</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 两个 base case</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 1.如果 root 为空，直接返回 null</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 2.如果 root 本身就是 p 或者 q</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 例如 root 是 p 节点，如果 q 存在于以 root 为根的树中，显然 root 就是最近公共祖先</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 即使 q 不存在于以 root 为根的树中，按照情况 3 的定义，也应该返回 root 节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> p </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> root </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> q</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">TreeNode</span><span class="token plain"> left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">lowestCommonAncestor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> q</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">TreeNode</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">lowestCommonAncestor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> q</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 在后序位置分情况讨论</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 情况 1，如果 p 和 q 都在以 root 为根的树中</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 那么 left 和 right 一定分别是 p 和 q（从 base case 看出）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 由于后序位置是从下往上，就好比从 p 和 q 出发往上走</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 第一次相交的节点就是这个 root，显然就是最近公共祖先</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 情况 2，如果 p 和 q 都不在以 root 为根的树中，直接返回 null</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 情况 3，如果 p 和 q 只有一个存在于 root 为根的树中，函数返回该节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> left </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> left</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>在前序位置搜索节点，如果是空节点直接返回，如果搜索到 <code>p</code> 或者 <code>q</code> 返回该节点，否则继续递归</p></blockquote><blockquote><p>在后序位置接收前序的返回值，如果 <code>left</code> 和 <code>right</code> 都不为空，说明分别是 <code>p</code> 和 <code>q</code>，当前 <code>root</code> 就是最近公共祖先，直接返回 <code>root</code> 节点。如果一个为空另一个不为空，说明找到一个节点，把这个节点向上传递，查找另一个节点，直到出现两个都不为空，此时 <code>root</code> 就是最近公共祖先，直接返回 <code>root</code> 节点</p></blockquote><p>📒 如何写对二分查找</p><ul><li>不要使用 <code>else</code>，而是把所有情况用 <code>else if</code> 写清楚</li><li>计算 <code>mid</code> 时需要防止溢出，使用 <code>left + (right - left) / 2</code> 先减后加这样的写法</li><li><code>while</code> 循环的条件 <code>&lt;=</code> 对应 <code>right</code> 初始值为 <code>nums.length - 1</code>，此时终止条件是 <code>left == right + 1</code>，例如 <code>[3, 2]</code></li><li>如果 <code>while</code> 循环的条件 <code>&lt;</code>，需要把 <code>right</code> 初始值改为 <code>nums.length</code>，此时终止条件是 <code>left == right</code>，例如 <code>[2, 2]</code>，这样会漏掉最后一个区间的元素，需要单独判断下</li><li>当 <code>mid</code> 不是要找的 <code>target</code> 时，下一步应该搜索 <code>[left, mid-1]</code> 或者 <code>[mid+1, right]</code>，对应 <code>left = mid + 1</code> 或者 <code>right = mid - 1</code></li><li>二分查找时间复杂度 <code>O(logn)</code></li></ul><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Solution</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">search</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 注意</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> left </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> left</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">mid</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> mid</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">mid</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        left </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 注意</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">mid</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        right </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 注意</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 前端三种 Content-Type</p><p><code>application/json</code>：这种应该是接口请求用到最多的，可以使用 <code>JSON.stringify()</code> 序列化得到，实际传递的内容类似于：</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token property" style="color:#36acaa">"a"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"111"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"b"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"222"</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>application/x-www-form-urlencoded</code>：这是表单提交对应的 Content-Type，实际上就是通过 body 传递 query 参数，如使用 HTML 的表单元素，浏览器会自动进行拼接，也可通过 <code>URLSearchParams</code> 拼接得到，实际传递的内容类似于：</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">a=</span><span class="token number" style="color:#36acaa">111</span><span class="token plain">&amp;b=</span><span class="token number" style="color:#36acaa">222</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>multipart/form-data</code>：是通过 <code>FormData</code> 对象构造出来的表单格式，通常用于文件上传，实际传递的报文内容类似于：</p><div class="language-http codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-http codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">POST /test.html HTTP/1.1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Host: example.org</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Content-Type: multipart/form-data;boundary="boundary"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--boundary</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Content-Disposition: form-data; name="field1"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">value1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--boundary</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Content-Disposition: form-data; name="field2"; filename="example.txt"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">value2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">--boundary--</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>顺便提一下，文件下载对应的 Content-Type 是 <code>application/octet-stream</code></p></blockquote><p>📒 如何理解 Node.js 模块</p><p>一个模块实际上可以看做一个 <code>once</code> 函数，头部的 <code>require</code> 命令可以看做入参，<code>module.exports</code> 可以看做返回值。</p><p>当首次加载一个模块的时候，就会运行这个模块代码，可以看做是调用一个函数，执行结束后得到导出的内容并被缓存，可以看做函数返回一个值。当再次加载这个模块，不再执行这个模块代码，而是直接从缓存中取值。</p><p>在一个函数中，我们知道可以使用 <code>return</code> 语句提前结束运行，那么在模块中如何实现呢，答案是使用 <code>process.exit(1)</code>：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> fs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"node:fs"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> path </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"node:path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> webpack </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"webpack"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> workDir </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">cwd</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> envFilePath </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">workDir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./.env.local"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> hasEnvFile </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">existsSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">envFilePath</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">hasEnvFile</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">exit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">mode</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"development"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">entry</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./src/index.js'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">output</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">path</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./dist'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">filename</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'[chunkhash].bundle.js'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">clean</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>这里注意下，<code>fs.exists()</code> 方法已经废弃了，但是 <code>fs.existsSync()</code> 仍然可用。此外还可使用 <code>fs.stat()</code> 或者 <code>fs.access()</code> 检查文件是否存在</p></blockquote><p>📒 <a href="https://juejin.cn/post/7070364142015610888" target="_blank" rel="noopener noreferrer">在 TIME_WAIT 状态的 TCP 连接，收到 SYN 后会发生什么？</a></p><p>📒 <a href="https://juejin.cn/post/7070683049049980941" target="_blank" rel="noopener noreferrer">一键部署 K8S 环境，10分钟玩转，这款开源神器实在太香了！</a></p><p>📒 charles 如何连接手机抓包</p><ul><li>确保手机和电脑连接的是同一个网络</li><li>首先打开 charles，会启动一个服务，查看端口：proxy -&gt; proxy setting</li><li>勾选 Enable transparent HTTP proxying</li><li>查看本机 IP</li><li>在手机上设置 http 代理服务器，输入 IP 和端口</li><li>此时 charles 会弹出提示，有新的连接，点击 allow</li></ul><p>📒 前端项目的 <code>.env</code> 文件是如何生效的，一句话总结</p><p>通过 <code>dotenv</code> 这个包解析 <code>.env</code> 文件，加载到 <code>process.ENV</code> 里面，这时候可以通过 <code>process.ENV.xxx</code> 访问到环境变量，适用于 Node.js 项目，但是由于浏览器环境访问不到 <code>process</code> 对象，所以对于前端项目，还需要使用 Webpack 的 DefinePlugin 在打包构建阶段将变量替换为对应的值。</p><p>📒 如何防止用户篡改 url 参数</p><blockquote><p>http://localhost:8080/codepc/live?codeTime=1646038261531&amp;liveId=5e24dd3cf03a&amp;sign=e8fe282676f584ceab7e35f84cbc52ff&amp;keyFrom=youdao</p></blockquote><p>前端的直播链接带有 <code>codeTime</code> 和 <code>liveId</code>，如何防止用户篡改。只需要后端在返回 <code>codeTime</code> 和 <code>liveId</code> 的时候，同时计算一个签名 <code>sign</code> 返回给前端，前端提交给后端的时候，同时传递三个参数，后端计算一个新的签名，与前端传过来的 <code>sign</code> 进行比对，如果一样就说明没有篡改。</p><p>但是计算签名用的 md5 是一个公开的算法，假如有人篡改了 <code>codeTime</code> 和 <code>liveId</code> ，只要他使用 md5 计算一个新的签名 <code>sign</code> ，这样传给后端校验必然可以通过。这就需要后端签名的时候拼接一个加密串进去，验签的时候也用这个加密串。这样由于别人不知道加密串，即便生成新的签名，后端校验也不会通过。</p><p>📒 <a href="https://juejin.cn/post/7070481262749679653" target="_blank" rel="noopener noreferrer">了解下Rust 模块使用方式</a></p><p>🌛 <a href="https://mp.weixin.qq.com/s/nrTpZ9b9RvfNsaEkJoHMvg" target="_blank" rel="noopener noreferrer">一文秒杀排列组合问题的 9 种题型</a></p><p>📒 Screenshot: 不依赖浏览器原生能力的截屏库</p><p>该库基于 MediaDevice API 来提供了易于截屏的抽象。如果你有兴趣可以来看看 GitHub 仓库</p><blockquote><p><a href="https://github.com/xataio/screenshot" target="_blank" rel="noopener noreferrer">https://github.com/xataio/screenshot</a></p></blockquote><p>📒 enum-xyz：使用 Proxy 实现 JavaScript 中的枚举</p><p>一个 js-weekly 的读者，分享的有趣实现思路。源码很短，推荐看一下</p><blockquote><p><a href="https://github.com/chasefleming/enum-xyz" target="_blank" rel="noopener noreferrer">https://github.com/chasefleming/enum-xyz</a></p></blockquote><p>📒 <a href="https://mp.weixin.qq.com/s/E82Kz14tnG4hRSmwZQmacQ" target="_blank" rel="noopener noreferrer">使用 React 和 Tailwind 创建阅读进度条</a></p><p>📒 <a href="https://juejin.cn/post/7070395594379886629" target="_blank" rel="noopener noreferrer">React内部让人迷惑的性能优化策略</a></p><p>📒 <a href="https://juejin.cn/post/7070377945553977357" target="_blank" rel="noopener noreferrer">Nest.js 基于 Express 但也不是完全基于</a></p><p>📒 如何使用代理模式优化代码</p><p>开发环境下打印日志：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> dev </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">env</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">NODE_ENV</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'development'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">createDevFn</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">cb</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter spread operator" style="color:#393A34">...</span><span class="token parameter">args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> dev </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">cb</span><span class="token punctuation" style="color:#393A34">(</span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> log </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createDevFn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">log</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"23333"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// "2333"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>异常捕获：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ExceptionsZone</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">exception</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Error：'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">exception</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> exception</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">stack</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">callback</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">callback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">handle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createExceptionZone</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter spread operator" style="color:#393A34">...</span><span class="token parameter">args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token maybe-class-name">ExceptionsZone</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">target</span><span class="token punctuation" style="color:#393A34">(</span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">request</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Promise</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">resolve</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">resolve</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> requestWithHandler </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createExceptionZone</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">requestWithHandler</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">res</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"请求结果："</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://juejin.cn/post/7070120806214271012" target="_blank" rel="noopener noreferrer">如何用 Proxy 更优雅地处理异常</a></p><p>📒 <a href="https://juejin.cn/post/7070109475419455519" target="_blank" rel="noopener noreferrer">VuePress 博客优化之开启 Algolia 全文搜索</a></p><p>📒 Git 分支操作流程</p><p>在 Git Flow 中，有两个长期存在且不会被删除的分支：<code>master</code> 和 <code>develop</code></p><ul><li><code>master</code> 主要用于对外发布稳定的新版本，该分支时常保持着软件可以正常运行的状态，不允许开发者直接对 master 分支的代码进行修改和提交。当需要发布新版本时，将会与 <code>master</code> 分支进行合并，发布时将会附加版本编号的 Git 标签</li><li><code>develop</code> 则用来存放我们最新开发的代码，这个分支是我们开发过程中代码中心分支，这个分支也不允许开发者直接进行修改和提交。程序员要以 <code>develop</code> 分支为起点新建 <code>feature</code> 分支，在 <code>feature</code> 分支中进行新功能的开发或者代码的修正</li></ul><blockquote><p>注意 <code>develop</code> 合并的时候，不要使用 <code>fast-farward merge</code>，建议加上 <code>--no-ff</code> 参数，这样在 <code>master</code> 上就会有合并记录</p></blockquote><p>除了这两个永久分支，还有三个临时分支：<code>feature branches</code>、<code>hotfixes</code> 以及 <code>release branches</code></p><ul><li><code>feature branches</code> 是特性分支，也叫功能分支。当你需要开发一个新的功能的时候，可以新建一个 <code>feature-xxx</code> 的分支，在里边开发新功能，开发完成后，将之并入 <code>develop</code> 分支中</li><li><code>hotfixes</code> 就是用来修复 BUG 的。当我们的项目上线后，发现有 BUG 需要修复，那么就从 <code>master</code> 上拉一个名为 <code>fixbug-xxx</code> 的分支，然后进行 BUG 修复，修复完成后，再将代码合并到 <code>master</code> 和 <code>develop</code> 两个分支中，然后删除 <code>hotfix</code> 分支</li><li><code>release branches</code> 是发版的时候拉的分支。当我们所有的功能做完之后，准备要将代码合并到 <code>master</code> 的时候，从 <code>develop</code> 上拉一个 <code>release-xxx</code> 分支出来，这个分支一般处理发版前的一些提交以及客户体验之后小 BUG 的修复（BUG 修复后也可以将之合并进 <code>develop</code>），不要在这个里边去开发功能，在预发布结束后，将该分支合并进 <code>develop</code> 以及 <code>master</code>，然后删除 <code>release</code></li></ul><p><img loading="lazy" alt="image" src="/assets/images/git-flow-fa1a8a6bb6b5732a66355fe4e2607960.png" width="1542" height="1002" class="img_ev3q"></p><p>📒 <a href="https://mp.weixin.qq.com/s/-u7tnhD8YoOV9bkC62S6Pg" target="_blank" rel="noopener noreferrer">大厂动态规划面试汇总，重量级干货，彻夜整理</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/1oDNxf5xHwlUUpJSVkqazg" target="_blank" rel="noopener noreferrer">通过几行 JS 就可以读取电脑上的所有数据？</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/A1uuU7DdBlUF-E6ZqlpOCw" target="_blank" rel="noopener noreferrer">百行代码带你实现通过872条Promise/A+用例的Promise</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/KIcn2TAwY58JGoWiz82Q2g" target="_blank" rel="noopener noreferrer">颜值爆表！Redis 官方可视化工具来啦，功能真心强大！</a></p><p>📒 程序员开源月刊《HelloGitHub》第 71 期</p><p><strong>C 项目</strong></p><p>chibicc：迷你 C 编译器。虽然它只是一个玩具级的编译器，但是实现了大多数 C11 特性，而且能够成功编译几十万行的 C 语言项目，其中包括 Git、SQLite 等知名项目。而且它项目结构清晰、每次提交都是精心设计、代码容易理解，对编译器感兴趣的同学可以从第一个提交开始学习</p><blockquote><p><a href="https://github.com/rui314/chibicc" target="_blank" rel="noopener noreferrer">https://github.com/rui314/chibicc</a></p></blockquote><p><strong>Go 项目</strong></p><p>nali：离线查询 IP 地理信息和 CDN 服务提供商的命令行工具</p><blockquote><p><a href="https://github.com/zu1k/nali" target="_blank" rel="noopener noreferrer">https://github.com/zu1k/nali</a></p></blockquote><p>revive：快速且易扩展的 Go 代码检查工具。它比 golint 更快、更灵活，深受广大 Go 开发者的喜爱</p><blockquote><p><a href="https://github.com/mgechev/revive" target="_blank" rel="noopener noreferrer">https://github.com/mgechev/revive</a></p></blockquote><p>go-chart：Go 原生图表库。支持折线图、柱状图、饼图等</p><blockquote><p><a href="https://github.com/wcharczuk/go-chart" target="_blank" rel="noopener noreferrer">https://github.com/wcharczuk/go-chart</a></p></blockquote><p><strong>Java 项目</strong></p><p>thingsboard：完全开源的物联网 IoT 平台。它使用行业的标准物联网协议 MQTT、CoAP 和 HTTP 连接设备，支持数据收集、处理、可视化和设备管理等功能。通过该项目可快速实现物联网平台搭建，从而成为众多大型企业的首选，行业覆盖电信、智慧城市、环境监测等</p><blockquote><p><a href="https://github.com/thingsboard/thingsboard" target="_blank" rel="noopener noreferrer">https://github.com/thingsboard/thingsboard</a></p></blockquote><p>from-java-to-kotlin：展示 Java 和 Kotlin 语法上差别的项目。让有 Java 基础的程序员可以快速上手 Kotlin</p><blockquote><p><a href="https://github.com/MindorksOpenSource/from-java-to-kotlin" target="_blank" rel="noopener noreferrer">https://github.com/MindorksOpenSource/from-java-to-kotlin</a></p></blockquote><p>⭐️ ⭐️ <a href="https://juejin.cn/post/7069555976717729805" target="_blank" rel="noopener noreferrer">「React进阶」react-router v6 通关指南</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[2月27日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月27日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月27日内容汇总"/>
        <updated>2022-02-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Vue diff 算法]]></summary>
        <content type="html"><![CDATA[<p>📒 Vue diff 算法</p><p>Vue2 diff 算法核心流程如下：</p><ul><li>diff 的入口函数为 <code>patch</code>，使用 <code>sameVnode</code> 比较节点是否相同，如相同则使用 <code>patchVnode</code> 继续进行深层比较，否则就使用 <code>createEle</code> 方法渲染出真实 DOM 节点，然后替换旧元素节点</li><li><code>sameVnode</code> 通过比较 <code>key</code> 值是否一样、标签名是否一样、是否都为注释节点、是否都定义 <code>data</code>、当标签为 <code>input</code> 时，<code>type</code> 是否相同来判断两个节点是否相同</li><li><code>patchVnode</code> 方法如何对节点深层比较<ul><li>拿到真实 DOM 的节点 <code>el</code>（即 <code>oldVnode.el</code>）</li><li>判断当前 <code>newVnode</code> 和 <code>oldVnode</code> 是否指向同一对象，如果是直接 <code>return</code></li><li>如果新旧虚拟节点是文本节点，且文本不一样，则直接将真实 DOM 中文本更新为新虚拟节点的文本；若文本没有变化，则继续对比新旧节点的 <code>children</code></li><li>如果 <code>oldVnode</code> 有子节点而 <code>newVnode</code> 没有，则删除 <code>el</code> 的子节点</li><li>如果 <code>oldVnode</code> 没有子节点而 <code>newVnode</code> 有，则将 <code>newVnode</code> 的子节点渲染出真实 DOM 添加到 <code>el</code>（Vue 源码中会判断是否有 <code>key</code> 重复）</li><li>如果两者都有子节点，则执行 <code>updateChildren</code> 函数比较子节点</li></ul></li><li><code>updateChildren</code> 是 diff 算法核心部分，当发现新旧虚拟节点的子节点都存在时，需要判断哪些节点是需要移动的，哪些节点是可以直接复用的，进而提高 diff 的效率<ul><li>通过 <strong>首尾指针法</strong>，在新旧子节点的首位定义四个指针，然后不断对比找到可复用的节点，同时判断需要移动的节点</li><li>非理想状态下只能通过节点映射的方式去找可复用节点，时间复杂度为 <code>O(n^2)</code></li><li>Vue3 的 diff 算法在非理想状态下的节点对比使用了最长递增子序列来处理，时间复杂度为 <code>O(nlgn)～O(n^2)</code></li></ul></li></ul><p><img loading="lazy" alt="image" src="/assets/images/patch-66a2ec2facba5395d7a9632528117c29.png" width="833" height="747" class="img_ev3q"></p><p><a href="https://mp.weixin.qq.com/s/8M-pJdKjF6bx5ijtSFKIcw" target="_blank" rel="noopener noreferrer">图解Diff算法——Vue篇</a></p><p><a href="https://juejin.cn/post/7067693810918096903" target="_blank" rel="noopener noreferrer">浅析 Snabbdom 中 vnode 和 diff 算法</a></p><p>📒 Leetcode 300 最长递增子序列</p><p>常规方式是使用动态规划，时间复杂度 <code>O(n^2)</code>。这里注意 <code>dp[i]</code> 的定义是 <strong>以 <code>nums[i]</code> 这个数结尾的最长递增子序列长度</strong>。</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Solution</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">lengthOfLIS</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 定义 dp 数组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列长度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> dp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 初始值填充 1（子序列至少包含当前元素自己）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Arrays</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fill</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dp</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> j </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> j </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> j</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 假设 dp[0...i-1] 都已知，需要求出 dp[i]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 只需要遍历 nums[0...i-1]，找到结尾比 nums[i] 小的子序列长度 dp[j]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 然后把 nums[i] 接到最后，就可以形成一个新的递增子序列，长度为 dp[j] + 1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 显然，可能形成很多种新的子序列，只需要选择最长的，作为 dp[i] 的值即可</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          dp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> dp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 遍历 dp 数组，找出最大值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> dp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> dp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 CSS 中的 <code>object-fit</code> 属性用法</p><p>在项目中有一个需求，图片尺寸较小时，需要保存图片原有大小，图片尺寸大于容器大小时，需要缩放以适合容器大小，同时保持原有比例。</p><p>查阅 MDN 文档可知，在 <code>&lt;img&gt;</code> 和 <code>&lt;video&gt;</code> 等替换元素上可以使用 <code>object-fit</code> 属性，用于设置替换元素该如何适配容器，可以取以下几个值：</p><ul><li><code>object-fit: fill</code>：图片被拉伸以适应容器，这种方式不会保持长宽比</li><li><code>object-fit: contain</code>：图片被缩放以适应容器，同时保持长宽比，如果图片与容器长宽比不匹配，较短边会留出空白</li><li><code>object-fit: cover</code>：图片被缩放以适应容器，同时保持长宽比，如果图片与容器长宽比不匹配，较长边会被剪裁</li><li><code>object-fit: none</code>：图片不会调整大小</li><li><code>object-fit: scale-down</code>：图片较小时使用 <code>none</code>，图片较大时使用 <code>contain</code></li></ul><p>综上，使用 <code>object-fit: scale-down</code> 就可以实现项目需求。</p><blockquote><p>注意 IE 11 不支持 <code>object-fit</code></p></blockquote><p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit" target="_blank" rel="noopener noreferrer">object-fit - MDN</a></p><p>📒 理解归并排序</p><p>归并排序就是对数组的左半边和右半边分别排序，然后再合并两个有序数组。</p><ul><li>归并排序的过程可以在逻辑上抽象成一棵二叉树，树上的每个节点的值可以认为是 <code>nums[lo..hi]</code>，叶子节点的值就是数组中的单个元素</li><li>然后，在每个节点的后序位置（左右子节点已经被排好序）的时候执行 <code>merge</code> 函数，合并两个子节点上的子数组</li><li>这个 <code>merge</code> 操作会在二叉树的每个节点上都执行一遍，执行顺序是二叉树后序遍历的顺序</li></ul><blockquote><p>一句话总结，归并排序实际上就是先对数组不断进行二分，分到只有一个元素为止，此时 <code>merge</code> 方法开始发挥作用，将两个元素为一组，合并为长度为 2 的有序数组，再将两个长度为 2 的有序数组为一组，合并为长度为 4 的有序数组，以此类推</p></blockquote><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Merge</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 用于辅助合并有序数组（不能原地合并，需要借助额外空间）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 避免递归中频繁分配和释放内存可能产生的性能问题</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 提前给辅助数组开辟内存空间</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    temp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 原地修改的方式对整个数组进行排序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 定义：将子数组 nums[lo..hi] 进行排序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lo </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 单个元素不用排序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 这样写是为了防止溢出，效果等同于 (hi + lo) / 2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 注意：对于无法整除的情况，Java 中 int 类型会自动向下取整</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> lo </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hi </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 先对左半部分数组 nums[lo..mid] 排序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mid</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 再对右半部分数组 nums[mid+1..hi] 排序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 将两部分有序数组合并成一个有序数组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">merge</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mid</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 将 nums[lo..mid] 和 nums[mid+1..hi] 这两个有序数组合并成一个有序数组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">merge</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> mid</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 先把 nums[lo..hi] 复制到辅助数组中</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 以便合并后的结果能够直接存入 nums</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      temp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 数组双指针技巧，合并两个有序数组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// i =&gt; 左半边数组起始下标</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// j =&gt; 右半边数组起始下标</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> j </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> p </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> lo</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> p </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> hi</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> p</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> mid </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 左半边数组已全部被合并，只需把右半边数组合并过来即可</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">j </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> hi </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 右半边数组已全部被合并，只需把左半边数组合并过来即可</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">temp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 将较小的元素合入，同时下标前进一位，此时是升序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 只要将 &gt; 改为 &lt; 就可以把结果改为降序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">j</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        nums</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> temp</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>归并排序时间复杂度为 <code>O(nlogn)</code></p></blockquote><p><a href="https://mp.weixin.qq.com/s/7_jsikVCARPFrJ6Hj1EYsg" target="_blank" rel="noopener noreferrer">归并排序的正确理解方式及运用</a></p><p>🌛 Leetcode 112 路径总和</p><p>判断是否存在 <strong>根节点到叶子节点</strong> 的路径，这条路径上所有节点值相加等于目标和&nbsp;<code>targetSum</code> 。如果存在，返回 <code>true</code> ；否则，返回 <code>false</code> 。</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Solution</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hasPathSum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TreeNode</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> targetSum</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">left </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">right </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">targetSum </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> leftResult </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hasPathSum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">left</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> targetSum </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> rightResult </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hasPathSum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">right</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> targetSum </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> leftResult </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> rightResult</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://mp.weixin.qq.com/s/Pq6eFNxjWpFIGdSL3ya7Vg" target="_blank" rel="noopener noreferrer">Podman 已成 Linux 官方标配！Docker 没戏了？</a></p><p>⭐️ <a href="https://juejin.cn/post/7000909761336049671" target="_blank" rel="noopener noreferrer">不懂动态规划？21道 LeetCode题目带你学会动态规划！</a></p><p>⭐️ <a href="https://juejin.cn/post/7067693810918096903" target="_blank" rel="noopener noreferrer">浅析 Snabbdom 中 vnode 和 diff 算法</a></p><p>📒 HTTP 缓存最佳实践</p><p>在配置 nginx 的时候，可以配置合理的缓存策略，例如：</p><ul><li>html 文件配置协商缓存</li><li>js、css、图片、字体等文件由于带有哈希，可以配置一年强缓存</li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>这里的缓存更新逻辑：</p><p>当 js、css 等静态资源文件修改后，文件哈希发生变化，对应引入 html 的文件地址也发生变化，等于 html 文件也被修改。因此浏览器端会获取到最新的 html 文件，然后根据带有哈希的路径加载最新的静态资源文件。</p></div></div><p>这样配置缓存之后，可以极大提升资源二次加载速度，进而提升用户体验。以上这些是从性能角度考虑的，从安全角度考虑，推荐如下配置：</p><ul><li>为了防止中介缓存，建议设置 <code>Cache-Control: private</code>，这可以禁用掉所有 <code>Public Cache</code>（比如代理），这就减少了攻击者跨界访问到公共内存的可能性</li><li>默认情况下，浏览器使用 <strong>URL</strong> 和 <strong>请求方法</strong> 作为缓存 key，这意味着，如果一个网站需要登录，不同用户的请求由于它们的请求URL和方法相同，数据会被缓存到一块内存里。如果我们请求的响应是跟请求的 <code>Cookie</code> 相关的，建议设置 <code>Vary: Cookie</code> 作为二级缓存 key</li></ul><p><a href="https://mp.weixin.qq.com/s/43pa04szJ2zU_IyVP4LraQ" target="_blank" rel="noopener noreferrer">HTTP 缓存别再乱用了！推荐一个缓存设置的最佳姿势！</a></p><p>📒 跨域，不止CORS</p><p>通常提到跨域问题的时候，相信大家首先会想到的是 <code>CORS</code> (Cross Origin Resource Sharing)，其实 <code>CORS</code> 只是众多跨域访问场景中安全策略的一种，类似的策略还有：</p><ul><li><code>COEP (Cross Origin Embedder Policy)</code>：跨源嵌入程序策略</li><li><code>COOP (Cross Origin Opener Policy)</code>：跨源开放者政策</li><li><code>CORP (Cross Origin Resource Policy)</code>：跨源资源策略</li><li><code>CORB (Cross Origin Read Blocking)</code>：跨源读取阻止</li></ul><p>为何有时候服务端没有给响应头设置 <code>Content-Type</code>，浏览器还能正确识别资源类型</p><p>当服务端没有设置 <code>Content-Type</code> 或者浏览器认为类型不正确时，浏览器会读取资源的字节流，进行 <strong>MIME 类型嗅探</strong>。这就可能导致一些敏感数据被提交到内存，攻击者随后可以利用 <code>Spectre</code> 之类的漏洞来潜在地读取该内存块。</p><blockquote><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing" target="_blank" rel="noopener noreferrer">https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing</a></p></blockquote><p>为了使我们的网站更加安全，建议所有网站都开启 <code>CORB</code>，只需要下面的操作：</p><ul><li>配置正确的 <code>Content-Type</code>（例如，HTML 资源设置 <code>text/html</code>）</li><li>开启 <code>X-Content-Type-Options: nosniff</code> 来禁止客户端进行自动 MIME 嗅探</li></ul><p><a href="https://mp.weixin.qq.com/s/k9_7Oc1zrQe6LMJB6D0qig" target="_blank" rel="noopener noreferrer">跨域，不止CORS</a></p><p><a href="https://juejin.cn/post/6855129007906963464" target="_blank" rel="noopener noreferrer">新的跨域策略：使用COOP、COEP为浏览器创建更安全的环境</a></p><p>📒 如何监听系统黑暗模式</p><p>在 CSS 中可以通过 <code>prefers-color-scheme</code> 媒体查询实现：</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token selector" style="color:#00009f">body</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color">black</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">background</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color">white</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token atrule rule" style="color:#00a4db">@media</span><span class="token atrule" style="color:#00a4db"> </span><span class="token atrule punctuation" style="color:#393A34">(</span><span class="token atrule property" style="color:#36acaa">prefers-color-scheme</span><span class="token atrule punctuation" style="color:#393A34">:</span><span class="token atrule" style="color:#00a4db"> dark</span><span class="token atrule punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token selector" style="color:#00009f">body</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color">white</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">background</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color">black</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在 JS 中可以使用 <code>window.matchMedia</code> 媒体查询：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> React </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ThemeName</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"light"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dark"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useTheme</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">themeName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setThemeName</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-function function" style="color:#d73a49">useState</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">ThemeName</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"light"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 设置初始皮肤</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">matchMedia</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"(prefers-color-scheme: dark)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">matches</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">setThemeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dark"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">setThemeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"light"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 监听系统颜色切换</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    window</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">matchMedia</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"(prefers-color-scheme: dark)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"change"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">event</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">matches</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token function" style="color:#d73a49">setThemeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dark"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token function" style="color:#d73a49">setThemeName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"light"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    themeName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    isDarkMode</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> themeName </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dark"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    isLightMode</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> themeName </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"light"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/matchMedia" target="_blank" rel="noopener noreferrer">https://developer.mozilla.org/zh-CN/docs/Web/API/Window/matchMedia</a></p></blockquote><blockquote><p>自定义 hook 实际上就是 mixin，把一段可复用的逻辑抽离出来</p></blockquote><p>📒 搜索 JS、Go、Java、Python 的第三方库</p><p><a href="https://openbase.com/" target="_blank" rel="noopener noreferrer">https://openbase.com/</a></p><p>例如搜索 Redux 的替代方案：</p><p><a href="https://openbase.com/js/redux/alternatives" target="_blank" rel="noopener noreferrer">https://openbase.com/js/redux/alternatives</a></p><p>⭐️ <a href="https://juejin.cn/post/7065875157268561957" target="_blank" rel="noopener noreferrer">React hooks 状态管理方案解析</a></p><p>📒 深入理解 React Native 的新架构</p><p>照 React Native 团队去年发表的一篇 博客 的说法，他们会在今年发布新的架构。本文将会详细介绍新架构的相关内容。</p><blockquote><p><a href="https://medium.com/coox-tech/deep-dive-into-react-natives-new-architecture-fb67ae615ccd" target="_blank" rel="noopener noreferrer">https://medium.com/coox-tech/deep-dive-into-react-natives-new-architecture-fb67ae615ccd</a></p></blockquote><p>📒 QUIC——快速UDP网络连接协议</p><ul><li>QUIC 的Stream流基于Stream ID+Offset进行包确认，流量控制需要保证所发送的所有包offset小于 <strong>最大绝对字节偏移量 （ maximum absolute byte offset ）</strong>， 该值是基于当前 <strong>已经提交的字节偏移量（offset of data consumed）</strong> 而进行确定的，QUIC会把连续的已确认的offset数据向上层应用提交。QUIC支持乱序确认，但本身也是按序（offset顺序）发送数据包</li><li>QUIC利用ack frame来进行数据包的确认，来保证可靠传输。一个ack frame只包含多个确认信息，没有正文</li><li>如果数据包N超时，发送端将超时数据包N重新设置编号M（即下一个顺序的数据包编号） 后发送给接收端</li><li>在一个数据包发生超时后，其余的已经发送的数据包依旧可以基于Offset得到确认，避免了TCP利用SACK才能解决的重传问题</li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>其实QUIC的乱序确认设计思想并不新鲜，大量网络视频流就是通过类似的基于UDP的RUDP、RTP、UDT等协议来实现快速可靠传输的。他们同样支持乱序确认，所以就会导致这样的观看体验：明明进度条显示还有一段缓存，但是画面就是卡着不动了，如果跳过的话视频又能够播放了</p></div></div><p><a href="https://juejin.cn/post/7066993430102016037" target="_blank" rel="noopener noreferrer">QUIC——快速UDP网络连接协议</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="QUIC" term="QUIC"/>
        <category label="React Native" term="React Native"/>
        <category label="React Hooks 状态管理" term="React Hooks 状态管理"/>
        <category label="黑暗模式" term="黑暗模式"/>
        <category label="HTTP 缓存" term="HTTP 缓存"/>
        <category label="Leetcode" term="Leetcode"/>
        <category label="归并排序" term="归并排序"/>
        <category label="CSS" term="CSS"/>
        <category label="Diff 算法" term="Diff 算法"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[2月20日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月20日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月20日内容汇总"/>
        <updated>2022-02-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 一致性哈希算法解决的问题]]></summary>
        <content type="html"><![CDATA[<p>📒 一致性哈希算法解决的问题</p><ul><li>大多数网站都是 <strong>多节点部署</strong>，需要根据不同场景使用不同的 <strong>负载均衡策略</strong></li><li>最简单的算法就是使用 <strong>加权轮询</strong>，这种场景建立在每个节点存储的数据都是相同的前提下，访问任意一个节点都能得到结果</li><li>当我们想提高系统的容量，就会将数据水平切分到不同的节点来存储，也就是将数据分布到了不同的节点。加权轮询算法是无法应对「分布式系统」的，因为分布式系统中，每个节点存储的数据是不同的，不是说任意访问一个节点都可以得到缓存结果的</li><li>这种场景可以使用 <strong>哈希算法</strong>，对同一个关键字进行哈希计算，每次计算都是相同的值，这样就可以将某个 key 映射到一个节点了，可以满足分布式系统的负载均衡需求</li><li>哈希算法最简单的做法就是进行取模运算，比如分布式系统中有 3 个节点，基于 <code>hash(key) % 3</code> 公式对数据进行了映射，如果计算后得到的值是 0，就说明该 key 需要去第一个节点获取</li><li>但是哈希算法存在一个问题，如果 <strong>节点数量发生了变化，也就是在对系统做扩容或者缩容时</strong>，意味取模哈希函数中基数的变化，这样会导致 <strong>大部分映射关系改变</strong>，必须迁移改变了映射关系的数据，否则会出现查询不到数据的问题</li><li>假设总数据条数为 M，哈希算法在面对节点数量变化时，<strong>最坏情况下所有数据都需要迁移，所以它的数据迁移规模是 O(M)</strong>，这样数据的迁移成本太高了</li><li>一致性哈希算法就很好地解决了分布式系统在扩容或者缩容时，发生过多的数据迁移的问题</li></ul><p><a href="https://juejin.cn/post/7067012046256078885" target="_blank" rel="noopener noreferrer">微信一面：什么是一致性哈希？用在什么场景？解决了什么问题？</a></p><p>📒 前端项目 nginx 配置总结</p><p>有段时间没搞项目部署了，结果最近有同事在部署前端项目的时候，访问页面路由，响应都是 404，排查了半天，这里再总结一下。</p><p>前端单页应用路由分两种：哈希模式和历史模式。</p><p>哈希模式部署不会遇到啥问题，但是一般只用于本地调试，没人直接部署到生产环境。历史模式的路由跳转通过 <code>pushState</code> 和 <code>replaceState</code> 实现，不会触发浏览器刷新页面，不会给服务器发送请求，且会触发 <code>popState</code> 事件，因此可以实现纯前端路由。</p><p>需要注意，使用历史模式的时候，还是有两种情况会导致浏览器发送请求给服务器：</p><ul><li>输入地址直接访问</li><li>刷新页面</li></ul><p>在这两种情况下，如果当前地址不是根路径，因为都是前端路由，服务器端根本不存在对应的文件，则会直接导致服务器直接响应 404。因此需要在服务器端进行配置：</p><div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">server {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  listen 80;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  server_name www.bili98.com;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  location / {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    root /root/workspace/ruoyi-ui/dist;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    # history 模式重点就是这里</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    try_files $uri $uri/ /index.html;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p><code>try_files</code> 的作用就是按顺序检查文件是否存在，返回第一个找到的文件。<code>$uri</code> 是 nginx 提供的变量，指当前请求的 URI，不包括任何参数</p><p>当请求静态资源文件的时候，命中 <code>$uri</code> 规则；当请求页面路由的时候，命中 <code>/index.html</code> 规则</p></div></div><p>此外，在部署的时候不使用根路径，例如希望通过这样的路径去访问 <code>/i/top.gif</code>，如果直接修改 <code>location</code> 发现还会响应 404：</p><div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">location /i/ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  root /data/w3;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  try_files $uri $uri/ /index.html;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>这是因为 <code>root</code> 是直接拼接 <code>root</code> + <code>location</code>，访问 <code>/i/top.gif</code>，实际会查找 <code>/data/w3/i/top.gif</code> 文件</p></blockquote><p>这种情况下推荐使用 <code>alias</code>：</p><div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">location /i/ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  alias /data/w3;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  try_files $uri $uri/ /index.html;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><code>alias</code> 是用 <code>alias</code> 替换 <code>location</code> 中的路径，访问 <code>/i/top.gif</code>，实际会查找 <code>/data/w3/top.gif</code> 文件</p></blockquote><p>现在页面部署成功了，但是接口请求会出错，这是因为还没有对接口请求进行代理，下面配置一下：</p><div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">location ^~ /prod-api/ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Host $http_host;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Real-IP $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header REMOTE-HOST $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_pass http://192.168.31.101:8080/;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>完整的 nginx 配置如下：</p><div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">server {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  listen 80;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  server_name www.bili98.com;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  location /ruoyi/ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    # 支持 /ruoyi 子路径访问</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alias /root/workspace/ruoyi-ui/dist;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    # history 模式重点就是这里</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    try_files $uri $uri/ /index.html;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    # html 文件不可设置强缓存，设置协商缓存即可</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    add_header Cache-Control 'no-cache, must-revalidate, proxy-revalidate, max-age=0';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  # 接口请求代理</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  location ^~ /prod-api/ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Host $http_host;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Real-IP $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header REMOTE-HOST $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_pass http://192.168.31.101:8080/;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  location ~* \.(?:css(\.map)?|js(\.map)?|gif|svg|jfif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    # 静态资源设置一年强缓存</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    add_header Cache-Control 'public, max-age=31536000';</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>location 的匹配规则：</p><ul><li><code>=</code> 表示精确匹配。只有请求的url路径与后面的字符串完全相等时，才会命中。</li><li><code>^~</code> 表示如果该符号后面的字符是最佳匹配，采用该规则，不再进行后续的查找。</li><li><code>~</code> 表示该规则是使用正则定义的，区分大小写。</li><li><code>~*</code> 表示该规则是使用正则定义的，不区分大小写。</li></ul><p>nginx 的匹配优先顺序按照上面的顺序进行优先匹配，而且 <strong>只要某一个匹配命中直接退出，不再进行往下的匹配</strong>。</p><p>剩下的普通匹配会按照 <strong>最长匹配长度优先级来匹配</strong>，就是谁匹配的越多就用谁。</p><p><a href="https://juejin.cn/post/7064378702779891749" target="_blank" rel="noopener noreferrer">前端到底用nginx来做啥</a></p><p><a href="https://juejin.cn/post/7048952689601806366" target="_blank" rel="noopener noreferrer">一份简单够用的 Nginx Location 配置讲解</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Bkss0lzPT-TI6GyGxMyn3Q" target="_blank" rel="noopener noreferrer">零基础理解 PostCSS 的主流程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/tQLG0HzR0bR_A8NLjTIChQ" target="_blank" rel="noopener noreferrer">Jest + React Testing Library 单测总结</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/UyvRTVWZDYnEBV9SL2Bbpg" target="_blank" rel="noopener noreferrer">使用lerna管理monorepo及发npm包实战教程</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/DswfPb6J1w2B_MWj1TjyOg" target="_blank" rel="noopener noreferrer">从源码中来，到业务中去，React性能优化终极指南</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/AfCfqhZy70v6MrSVt5_8uw" target="_blank" rel="noopener noreferrer">React核心设计原理--（React Fiber）异步执行调度</a></p><p>📒 如何在浏览器使用后端语言进行编程</p><p>你可能会认为这是关于使用 WebAssembly 在浏览器中运行 Python 之类的代码，但这并不是作者想分享的。作者提到的是通过服务端的 WebSocket 连接浏览器平台，由服务端处理 HTML 渲染更新到浏览器，这种方案日益流行，并且已经在 Elixir 和 Rails 全栈框架中支持。</p><blockquote><p><a href="https://github.com/readme/featured/server-side-languages-for-front-end" target="_blank" rel="noopener noreferrer">https://github.com/readme/featured/server-side-languages-for-front-end</a></p></blockquote><p>📒 正则表达式如何实现千分位分隔符</p><p>实现如下的需求：</p><ul><li>从后往前每三个数字前加一个逗号</li><li>开头不能加逗号</li></ul><p>这样看起来非常符合 <code>(?=p)</code> 的规律，<code>p</code> 可以表示每三个数字，要添加逗号所处的位置正好是 <code>(?=p)</code> 匹配出来的位置。</p><p>第一步，先尝试把最后一个逗号弄出来：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">"300000000"</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">replace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex" style="color:#36acaa">(?=\d{3}$)</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">","</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// '300000,000'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>第二步，把所有逗号都弄出来：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">"300000000"</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">replace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex" style="color:#36acaa">(?=(\d{3})+$)</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-flags" style="color:#36acaa">g</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">","</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ',300,000,000'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>使用括号把一个 <code>p</code> 模式变成一个整体</p></blockquote><p>第三步，去掉首位的逗号：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">"300000000"</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">replace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex" style="color:#36acaa">(?!^)(?=(\d{3})+$)</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-flags" style="color:#36acaa">g</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">","</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// '300,000,000'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>⭐️ <a href="https://juejin.cn/post/7065197280223035422" target="_blank" rel="noopener noreferrer">如何使用高阶函数编程提升代码的简洁性</a></p><p>📒 React Router v6 和私有路由 (也称作保护路由)</p><blockquote><p><a href="https://www.robinwieruch.de/react-router-private-routes/" target="_blank" rel="noopener noreferrer">https://www.robinwieruch.de/react-router-private-routes/</a></p></blockquote><p>📒 React Router v6 的身份验证简介</p><p>在一个简单的示例应用程序中，通过 React Router v6 实现身份验证的实用演练。</p><blockquote><p><a href="https://www.robinwieruch.de/react-router-authentication/" target="_blank" rel="noopener noreferrer">https://www.robinwieruch.de/react-router-authentication/</a></p></blockquote><p>📒 Etsy 从 React 15.6 迁移到了 Preact （而不是 React 16）</p><p>在这篇 关于在 Etsy 更新 React 的文章中，对这个决定有一个完整的解释。但事实证明，拥有相同 API 的小型 React 替代品 Preact 是他们的正确选择。</p><blockquote><p><a href="https://twitter.com/sangster/status/1486382892326563845" target="_blank" rel="noopener noreferrer">https://twitter.com/sangster/status/1486382892326563845</a></p></blockquote><p>📒 Promise 两点总结</p><p>不建议在 <code>Promise</code> 里面使用 <code>try...catch</code>，这样即使 <code>Promise</code> 内部报错，状态仍然是 <code>fullfilled</code>，会进入 <code>then</code> 方法回调，不会进入 <code>catch</code> 方法回调。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">request</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Promise</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">resolve</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> reject</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"ok"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">request</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">res</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"请求结果："</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> res</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">err</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 由于在 Promise 中使用了 try...catch</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 因此即使 Promise 内部报错，也不会被 catch 捕捉到</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><code>Promise</code> 内部的异常，老老实实往外抛就行，让 <code>catch</code> 方法来处理，符合单一职责原则</p></blockquote><p>不建议在 <code>async</code> 函数中，既不使用 <code>await</code>，也不使用 <code>return</code>，这样就算内部的 <code>Promise</code> reject 也无法捕捉到：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleFetchUser</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">userList</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 这里既没有使用 await，也没有使用 return</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token known-class-name class-name">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">userList</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">u</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">request</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">u</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">handleFetchUser</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">userList</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">res</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 由于没有返回值，这里拿到的是 undefined</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">err</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 即使 handleFetchUser 内部的 Promise reject</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// async 函数返回的 Promise 仍然是 fullfilled</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 此时仍然会进入 then 方法回调，无法被 catch 捕捉到</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>如果确实有这种需求，建议不要使用 <code>async</code> 函数，直接改用普通函数即可</p></blockquote><p>📒 Rollup 配置</p><p><a href="https://juejin.cn/post/6844903970469576718" target="_blank" rel="noopener noreferrer">前端组件/库打包利器rollup使用与配置实战</a></p><p>📒 Docker 使用，Gitlab CI 实践</p><p><a href="https://juejin.cn/post/7064906701941506061" target="_blank" rel="noopener noreferrer">GitLab CI 从入门到实践</a></p><p>📒 总结一下 Babel 插件开发基本操作</p><blockquote><p><a href="https://github.com/BoBoooooo/AST-Learning" target="_blank" rel="noopener noreferrer">https://github.com/BoBoooooo/AST-Learning</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7064909191210598408" target="_blank" rel="noopener noreferrer">记一次 Vue2 迁移 Vue3 的实践总结</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[2月13日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月13日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月13日内容汇总"/>
        <updated>2022-02-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 浏览器技术架构的演进过程和背景]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://juejin.cn/post/7035791029814951950" target="_blank" rel="noopener noreferrer">浏览器技术架构的演进过程和背景</a></p><p>📒 <a href="https://juejin.cn/post/7059408852390772767" target="_blank" rel="noopener noreferrer">从chromium源码来窥探浏览器的渲染</a></p><p>📒 <a href="https://juejin.cn/post/6951649464637636622" target="_blank" rel="noopener noreferrer">从 0 开始手把手带你搭建一套规范的 Vue3.x 项目工程环境</a></p><p>📒 为什么 React 中要使用 immutable 数据流</p><p>在 <code>PureComponent</code> 和 <code>memo</code> 中会将新旧 props 进行 <strong>浅层比对</strong>，逻辑非常简单：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">shallowEqual</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter literal-property property" style="color:#36acaa">objA</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> mixed</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> </span><span class="token parameter literal-property property" style="color:#36acaa">objB</span><span class="token parameter operator" style="color:#393A34">:</span><span class="token parameter"> mixed</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> boolean </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 下面的 is 相当于 === 的功能</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 只是对 + 0 和 - 0，以及 NaN 和 NaN 的情况进行了特殊处理</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 第一关：基础数据类型直接比较出结果</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">is</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">objA</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> objB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 第二关：只要有一个不是对象数据类型就返回 false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> objA </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'object'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    objA </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> objB </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'object'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    objB </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 第三关：在这里已经可以保证两个都是对象数据类型，比较两者的属性数量</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> keysA </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">keys</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">objA</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> keysB </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">keys</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">objB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">keysA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> keysB</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 第四关：比较两者的属性是否相等，值是否相等</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> keysA</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">hasOwnProperty</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">objB</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> keysA </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token operator" style="color:#393A34">!</span><span class="token function" style="color:#d73a49">is</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">objA </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">keysA </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> objB </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">keysA </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>但浅层比较相当于只是比较第一层，还是会存在一些问题，如果修改深层嵌套的对象，浅层比较会认为相等。</p><p>为解决这个问题，可以手动在 <code>shouldComponentUpdate</code> 钩子中实现深层比对，但缺点就是浪费性能。最好的解决方案就是使用 immutable 数据流。immutable 对象内部采用的是多叉树的结构，只要有节点被修改，那么该节点和与之相关的所有父节点会直接拷贝到一个新的对象中（创建一个新的引用）。也就是说，修改任意一个子节点，改动都会冒泡到根节点，这样浅比较就能感知到数据改变了。</p><p><a href="https://juejin.cn/book/6844733816460804104/section/6844733816548884487" target="_blank" rel="noopener noreferrer">React Hooks 与 Immutable 数据流实战</a></p><p>📒 操作 JavaScript 的 AST</p><p><code>acorn</code>、<code>Espree</code>、<code>@babel/parser</code> 三种解析器用法说明</p><p><a href="https://juejin.cn/post/7061808830274863118" target="_blank" rel="noopener noreferrer">操作 JavaScript 的 AST</a></p><p>📒 React fiber 架构浅析</p><p>在 React 16 之前，vdom 以递归的方式进行 patch 和渲染，一个 vdom 节点可以表示如下：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">VNode</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  props</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  children</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> VNode</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在 React 16 之后引入了 fiber 架构，vdom 不再直接渲染，而是先转成 fiber，一个 fiber 节点可以表示如下：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">FiberNode</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  props</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  dom</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> HTMLElement</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 提前创建 dom 节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  child</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> FiberNode</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  sibling</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> FiberNode</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> FiberNode</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  effectTag</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 做 diff，确定是增、删还是改</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在 fiber 架构中，将 vdom 树结构转成了链表，每个 fiber 节点的 <code>child</code> 关联第一个子节点，然后通过 <code>sibling</code> 串联同一层级的节点，所有的节点可以 <code>return</code> 到父节点：</p><p><img loading="lazy" alt="image" src="/assets/images/react-fiber-14eec4cdb0efcfaf84bd232c4dbdfede.png" width="1668" height="1214" class="img_ev3q"></p><p>先把 vdom 转 fiber，也就是 reconcile 的过程，因为 fiber 是链表，就可以打断，用 schedule 来空闲时调度（requestIdleCallback）就行，最后全部转完之后，再一次性 render，这个过程叫做 commit。</p><p>schedule 就是通过空闲调度每个 fiber 节点的 reconcile（vdom 转 fiber），全部 reconcile 完了就执行 commit。</p><p>reconcile 除了将 vdom 转 fiber 外，还会做两件事：一个是 <strong>提前创建对应的 dom 节点</strong>，另一个是 <strong>做 diff，确定是增、删还是改</strong>，通过 schdule 的调度，最终把整个 vdom 树转成了 fiber 链表。</p><p>commit 就是对 dom 的增删改，把 reconcile 产生的 fiber 链表一次性添加到 dom 中，因为 dom 节点都提前创建好了、是增是删还是改也都知道了，所以这个阶段很快。每个 fiber 节点的渲染就是按照 child、sibling 的顺序以此插入到 dom 中，这里每个 fiber 节点都要往上找它的父节点（之前保存的 <code>return</code> 指针），因为我们只是新增，那么只需要 <code>appendChild</code> 就行。</p><p><a href="https://juejin.cn/post/7063321486135656479" target="_blank" rel="noopener noreferrer">手写简易版 React 来彻底搞懂 fiber 架构</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Hnp2XddZPp3WAHrXBqEyAQ" target="_blank" rel="noopener noreferrer">Chrome 99新特性：@layers 规则浅析</a></p><p>📒 WebVM.io：基于 Web 的“无服务端”虚拟 Linux 环境</p><p>浏览器端运行的 Linux 环境，基于 JavaScript 和 WebAssembly 的 CheerpX x86 虚拟化引擎驱动。虽然它不是一个完全基于 JavaScript 的项目，但它很好地展示了 Web 技术的发展程度。它已经内置了 Node v10.24.0，但要注意它首次加载速度可能会有点慢。</p><blockquote><p><a href="https://webvm.io/" target="_blank" rel="noopener noreferrer">https://webvm.io/</a></p></blockquote><p>这里有一篇关于它如何工作的文章。</p><blockquote><p><a href="https://leaningtech.com/webvm-server-less-x86-virtual-machines-in-the-browser/" target="_blank" rel="noopener noreferrer">https://leaningtech.com/webvm-server-less-x86-virtual-machines-in-the-browser/</a></p></blockquote><p>📒 如何使用 Vue 3、Vite、Pinia 开发应用程序</p><p>非常完善的开发、测试、部署指南。</p><blockquote><p><a href="https://labs.pineview.io/learn-how-to-build-test-and-deploy-a-single-page-app-with-vue-3-vite-and-pinia/" target="_blank" rel="noopener noreferrer">https://labs.pineview.io/learn-how-to-build-test-and-deploy-a-single-page-app-with-vue-3-vite-and-pinia/</a></p></blockquote><p>📒 用代码分割来提高打包 JavaScript 时的性能</p><blockquote><p><a href="https://www.smashingmagazine.com/2022/02/javascript-bundle-performance-code-splitting/" target="_blank" rel="noopener noreferrer">https://www.smashingmagazine.com/2022/02/javascript-bundle-performance-code-splitting/</a></p></blockquote><p>📒 提升 VSCode 扩展插件的运行速度</p><p>插件开发者必读</p><p><img loading="lazy" alt="image" src="/assets/images/vscode-arch-a05196452e003d5e7edbf062c71e5dfe.webp" width="1080" height="431" class="img_ev3q"></p><blockquote><p><a href="https://jason-williams.co.uk/speeding-up-vscode-extensions-in-2022" target="_blank" rel="noopener noreferrer">https://jason-williams.co.uk/speeding-up-vscode-extensions-in-2022</a></p></blockquote><p>📒 Babel 发布 v7.17.0</p><p>该版本对 <strong>装饰器提案</strong> 的支持已稳定，还对装饰器的解析和转换进行了支持。</p><blockquote><p><a href="https://babeljs.io/blog/2022/02/02/7.17.0" target="_blank" rel="noopener noreferrer">https://babeljs.io/blog/2022/02/02/7.17.0</a></p></blockquote><p>📒 使用 Streams 模块构建高性能的 Node 应用</p><blockquote><p><a href="https://blog.appsignal.com/2022/02/02/use-streams-to-build-high-performing-nodejs-applications.html" target="_blank" rel="noopener noreferrer">https://blog.appsignal.com/2022/02/02/use-streams-to-build-high-performing-nodejs-applications.html</a></p></blockquote><p>📒 Node.js 新增 Fetch API</p><p>对 Fetch API （一般是浏览器端用来获取资源）的支持已经合并到 Node.js，将在提供 <code>‑‑experimental‑fetch</code> 标志后可以开启，Node v18 或者更高版本会默认启用。</p><blockquote><p><a href="https://fusebit.io/blog/node-fetch/" target="_blank" rel="noopener noreferrer">https://fusebit.io/blog/node-fetch/</a></p></blockquote><p>⭐️ <a href="https://mp.weixin.qq.com/s/triP_hXILSWq37DIGz4VNg" target="_blank" rel="noopener noreferrer">来自未来，2022 年的前端人都在做什么?</a></p><p>⭐️ <a href="https://juejin.cn/post/7052918009555320839" target="_blank" rel="noopener noreferrer">最全的前端性能定位总结</a></p><p>📒 <a href="https://juejin.cn/post/7061556434692997156" target="_blank" rel="noopener noreferrer">接近天花板的TS类型体操，看懂你就能玩转TS了</a></p><p>📒 <a href="https://juejin.cn/post/7057325585705467918" target="_blank" rel="noopener noreferrer">2022年必会Vue3.0学习 （强烈建议）</a></p><p>📒 <a href="https://juejin.cn/post/7062496975454732301" target="_blank" rel="noopener noreferrer">如何利用 SCSS 实现一键换肤</a></p><p>📒 <a href="https://juejin.cn/post/7062258342546620423" target="_blank" rel="noopener noreferrer">手写 JS 引擎来解释一道赋值面试题</a></p><p>📒 10 分钟讲述 React 的故事</p><blockquote><p><a href="https://www.youtube.com/watch?v=Wm_xI7KntDs" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=Wm_xI7KntDs</a></p></blockquote><p>📒 2022 年值得关注的 React 趋势</p><blockquote><p><a href="https://www.chakshunyu.com/blog/what-you-should-definitely-look-out-for-in-react-in-2022/" target="_blank" rel="noopener noreferrer">https://www.chakshunyu.com/blog/what-you-should-definitely-look-out-for-in-react-in-2022/</a></p></blockquote><p>📒 React 18 中的自动批处理（Automatic Batching）</p><blockquote><p><a href="https://blog.bitsrc.io/automatic-batching-in-react-18-what-you-should-know-d50141dc096e?gi=aa52794e9a07" target="_blank" rel="noopener noreferrer">https://blog.bitsrc.io/automatic-batching-in-react-18-what-you-should-know-d50141dc096e?gi=aa52794e9a07</a></p></blockquote><p>📒 <a href="https://github.com/signavio/react-mentions" target="_blank" rel="noopener noreferrer">React Mentions：在 Textarea 中提及某人</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[2月6日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月6日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/2月6日内容汇总"/>
        <updated>2022-02-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 很多人上来就删除的 package.json，还有这么多你不知道的]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://segmentfault.com/a/1190000039684460" target="_blank" rel="noopener noreferrer">很多人上来就删除的 package.json，还有这么多你不知道的</a></p><p>📒 React hooks 使用注意事项</p><p>惰性初始化 State：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// React hook 会在每次组件重新渲染的时候调用</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setCount</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function maybe-class-name" style="color:#d73a49">ExpensiveCal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 如果 useState 的初始值需要通过复杂计算获取，可以传入一个函数惰性初始化</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这个函数只会在组件挂载的时候执行一次，后续更新都不会执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setCount</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">ExpensiveCal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>不需要视图渲染的变量，不要用 <code>useState</code>：</p><div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">FC</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// count 与视图渲染无关</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 如果使用 useState，每次 count 变化都会触发组件重新渲染</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setCount</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 这里推荐使用 useRef</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useRef</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">handleClick</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">setCount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">handleClick</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">Counter</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>函数式更新：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setCount</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 下面这样虽然调用了两次</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 但由于一次渲染中获取的 count 都是闭包中老的值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 因此最终 count 还是 1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">setCount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">count </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">setCount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">count </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 如果要获取到上一次更新的值，可以使用函数式更新</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 最终 count 为 2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">setCount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">c</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">setCount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">c</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>useEffect</code> 清除副作用：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useEffect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// useEffect 的回调函数中可以返回一个函数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 这个函数会在组件卸载的时候执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 用于清理各种事件监听器、定时器等</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>React.useCallback</code> 需要配合 <code>React.memo</code> 使用，其中任意一个单独使用是没用的。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p><code>React.useCallback</code> 使用的一个场景是：</p><ul><li>一个父组件中有一个复杂的自定义组件，需要传入事件处理函数作为 prop，为避免父组件渲染导致该子组件重新渲染，使用 <code>React.memo</code> 包裹一下；</li><li>包裹之后发现父组件重新渲染，该子组件还是会重新渲染，这是因为事件处理函数在父组件每次渲染的时候都重新生成，因而传入子组件的 prop 变化导致 <code>React.memo</code> 失效；</li><li>将事件处理函数用 <code>React.useCallback</code> 包裹一下，对事件处理函数进行缓存，避免每次父组件渲染都重新生成，这样父组件重新渲染就不会导致子组件重新渲染；</li><li>需要注意 <code>React.useCallback</code> 缓存本身也是有性能开销的，因此只有在子组件渲染比较昂贵的时候，才进行缓存处理；</li></ul></div></div><p>📒 Golang 中的包管理机制</p><p>Golang 中的包管理使用 <code>go.mod</code> 文件，可以使用下面的命令在项目根目录初始化一个 <code>go.mod</code>：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 初始化一个 v0 或者 v1 的包</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ go mod init example.com/m</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 初始化指定版本的包</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ go mod init example.com/m/v2</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>安装依赖：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ go get -u github.com/gin-gonic/gin</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><code>-u</code> 安装全局变量类似 <code>npm i -g cobra</code></p></blockquote><p>如果直接下载请求超时，可以设置镜像源：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ go </span><span class="token function" style="color:#d73a49">env</span><span class="token plain"> -w </span><span class="token assign-left variable" style="color:#36acaa">GO111MODULE</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">on</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ go </span><span class="token function" style="color:#d73a49">env</span><span class="token plain"> -w </span><span class="token assign-left variable" style="color:#36acaa">GOPROXY</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">https://goproxy.cn,https://goproxy.io,direct</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>类似 <code>npm config set registry</code></p></blockquote><p>安装之后就可以看到 <code>go.mod</code> 里面多了些东西：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">module github</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">com</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">Jiacheng787</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">goexample</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">go</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.17</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">require </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    github</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">com</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">gin</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">gonic</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">gin v1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token number" style="color:#36acaa">7.7</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>下载项目依赖：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ go get ./</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://zhuanlan.zhihu.com/p/103534192/" target="_blank" rel="noopener noreferrer">三分钟掌握Go mod常用与高级操作</a></p><p>📒 如何解决 CSS 兼容性问题</p><p>对于 JS 的兼容性，我们可以使用 Babel 进行语法转换以及对 API 进行 polyfill。那么对于 CSS 的兼容性如何适配呢？可以使用 PostCSS，最完善的 CSS 工程化解决方案：</p><ul><li><code>autoprefixer</code>：根据 Can I Use 的数据给 CSS 属性添加厂商前缀</li><li><code>postcss-preset-env</code>：允许使用一些提案阶段的特性</li></ul><p>此外还提供各种插件：</p><ul><li><code>postcss-modules</code>：CSS 模块化</li><li><code>postcss-initial</code>：重置默认样式</li><li><code>sugarss</code>：支持缩进语法编写 CSS 样式</li></ul><blockquote><p><a href="https://github.com/postcss/postcss" target="_blank" rel="noopener noreferrer">https://github.com/postcss/postcss</a></p></blockquote><p>📒 <a href="https://www.digitalocean.com/community/tutorials/how-to-process-images-in-node-js-with-sharp#step-3-resizing-changing-image-format-and-compressing-images" target="_blank" rel="noopener noreferrer">How To Process Images in Node.js With Sharp</a></p><p>📒 字节跳动开源项目</p><ul><li><a href="https://github.com/bytedance/IconPark" target="_blank" rel="noopener noreferrer">IconPark - 支持多种主题、跨平台的图标库</a></li><li><a href="https://github.com/bytedance/xgplayer" target="_blank" rel="noopener noreferrer">xgplayer - HTML5 视频播放器</a></li><li><a href="https://github.com/bytedance/sonic" target="_blank" rel="noopener noreferrer">sonic - 基于 JIT 技术的开源全场景高性能 JSON 库</a></li><li><a href="https://github.com/bytedance/bytemd" target="_blank" rel="noopener noreferrer">bytemd - 字节出品的 markdown 编辑器</a></li></ul><p>📒 前端项目 babel 配置</p><p>编译一个前端项目，一般需要安装如下依赖：</p><ul><li><code>@babel/core</code>：核心库</li><li><code>babel-loader</code>：配合 Webpack 打包场景使用</li><li><code>@babel/preset-env</code>：语法转换的预设插件集，同时支持 api 兼容</li><li><code>@babel/preset-react</code>：编译 React 的 JSX 语法</li><li><code>@babel/preset-typescript</code>：可选，编译 TypeScript 语法</li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p><code>@babel/core</code> 是核心库，里面包含：</p><ul><li><code>@babel/parser</code>：一个 ast 解析器，之前叫 Babylon，基于 acorn 魔改而来，负责解析生成 ast</li><li><code>@babel/traverse</code>：负责通过访问者模式遍历并操作 ast 节点</li><li><code>@babel/generator</code>：负责根据 ast 生成代码</li></ul><p><code>babel-loader</code> 用于配合 Webpack 打包场景使用，如果想通过命令行的方式使用，则需要安装 <code>@babel/cli</code></p><p><code>@babel/preset-env</code> 的 api 兼容是通过引入 <code>core-js</code> polyfill 实现的。<code>core-js</code> 引入有多种方式，可以配置 <code>entry</code>，即在入口文件处根据根据 browserslist 配置需要适配的目标环境全量引入 polyfill，也可以配置 <code>usage</code>，根据 browserslist 配置和实际用的 api 按需引入 polyfill。<code>@babel/preset-env</code> 是通过全局污染的形式引入的，一般在前端项目中没问题，但是作为第三方库就不合适了，这时候需要使用 <code>@babel/plugin-transform-runtime</code> 通过沙箱机制引入 polyfill，这种引入方式有个缺点，无法根据 browserslist 配置动态调整引入的 polyfill。</p><p><code>@babel/preset-typescript</code> 实际上就是简单删除掉类型注解。因为 Babel 是单文件处理，不可能进行类型检查，类型检查可以交给 VSCode 插件，或者 <code>ForkTsCheckerWebpackPlugin</code> 单独起一个进程进行类型检查，这时候 tsc 的作用就是类型检查器，需要配置 <code>"noEmit": true</code>。</p></div></div><p>📒 写文章集合</p><ul><li>Redux 在完善下，增加 UI-binding</li><li>深入源码分析 Koa 中间件与洋葱圈模型</li><li>前端项目的 env 文件是如何被加载的</li><li>Webpack 打包的图片和字体的哈希是如何生成的 - file-loader 源码分析</li></ul>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[1月30日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月30日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月30日内容汇总"/>
        <updated>2022-01-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 推荐使用 stylus]]></summary>
        <content type="html"><![CDATA[<p>📒 推荐使用 stylus</p><p>推荐使用 stylus，所有的 <code>{}</code>、<code>:</code> 以及 <code>;</code> 都是可省略的：</p><div class="language-stylus codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-stylus codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token selector" style="color:#00009f">.page</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property-declaration property" style="color:#36acaa">padding-bottom</span><span class="token property-declaration"> </span><span class="token property-declaration number" style="color:#36acaa">2</span><span class="token property-declaration unit">rem</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property-declaration property" style="color:#36acaa">display</span><span class="token property-declaration"> block</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token selector" style="color:#00009f">.content-lock</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property-declaration property" style="color:#36acaa">display</span><span class="token property-declaration"> none</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property-declaration property" style="color:#36acaa">text-align</span><span class="token property-declaration"> center</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property-declaration property" style="color:#36acaa">padding</span><span class="token property-declaration"> </span><span class="token property-declaration number" style="color:#36acaa">2</span><span class="token property-declaration unit">rem</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property-declaration property" style="color:#36acaa">font-size</span><span class="token property-declaration"> </span><span class="token property-declaration number" style="color:#36acaa">1</span><span class="token property-declaration unit">em</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>这就类似为什么建议使用 <code>yaml</code> 替代 <code>json</code>，在 <code>yaml</code> 中不需要引号，简单省事</p></blockquote><p>📒 页面性能优化技巧</p><p>分析代码执行耗时可以通过 <strong>火焰图</strong>，分析内存占用情况可以通过 <strong>堆快照</strong>。</p><p>⭐️ <a href="https://github.com/streamich/react-use" target="_blank" rel="noopener noreferrer">react-use - 一个 React Hooks 库</a></p><p>📒 Next.js 提供的渲染方式</p><ul><li>SSR: Server-side rendering (服务端渲染)</li><li>SSG: Static-site generation (静态站点生成)</li><li>CSR: Client-side rendering (客户端渲染)</li><li>Dynamic routing (动态路由)</li><li>ISR: Incremental Static Regeneration (增量静态再生)</li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>CSR、SSR、SSG 的区别？</p><p>CSR 是在用户浏览器端调接口请求数据进行渲染；SSR 是在用户请求页面的时候，服务器端请求数据并进行渲染；SSG 是直接在构建阶段就进行渲染，一般用于文档网站。</p></div></div><p>📒 <a href="https://zhuanlan.zhihu.com/p/461945753" target="_blank" rel="noopener noreferrer">Node 案发现场揭秘 —— 未定义 “window” 对象引发的 SSR 内存泄露</a></p><p>📒 <a href="https://juejin.cn/post/6844903881390964744" target="_blank" rel="noopener noreferrer">从头开始，彻底理解服务端渲染原理(8千字汇总长文)</a></p><p>📒 <a href="https://juejin.cn/post/7039036362653171742" target="_blank" rel="noopener noreferrer">【7000字】一晚上爆肝浏览器从输入到渲染完毕原理</a></p><p>📒 <a href="https://juejin.cn/post/7055101823442485255" target="_blank" rel="noopener noreferrer">爆肝三天，学习Scss-看这篇就够了</a></p><p>⭐️ <a href="https://juejin.cn/post/7057354419888717855" target="_blank" rel="noopener noreferrer">编译技术在前端的实践（二）—— Antlr 及其应用</a></p><p>⭐️ <a href="https://juejin.cn/post/6989509925844041742" target="_blank" rel="noopener noreferrer">编译技术在前端的实践（一）—— 编译原理基础</a></p><p>📒 如何实从零实现 husky</p><p>看下如何做 <strong>测试驱动开发</strong></p><p><a href="https://juejin.cn/post/7057345959402930183" target="_blank" rel="noopener noreferrer">从零实现husky</a></p><p>📒 如何让一个构造函数只能用 <code>new</code> 调用</p><p>使用 ES6 class 会检查是否通过 <code>new</code> 调用，而普通构造函数不会检查是否通过 <code>new</code> 调用，这种情况下需要手动进行判断，通常都会这样做：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">MyClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">instanceof</span><span class="token plain"> </span><span class="token class-name">MyClass</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"MyClass must call with new"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这样的话，如果不通过 <code>new</code> 调用，就会抛出异常。其实更好的方案是进行兼容处理，即不使用 <code>new</code> 调用，自动改用 <code>new</code> 调用：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">MyClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">instanceof</span><span class="token plain"> </span><span class="token class-name">MyClass</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 如果没有使用 `new` 调用，自动改用 `new` 调用</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 通过 `return` 中断函数执行，并返回创建的实例</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">MyClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 为什么 React Hook 底层使用链表而不是数组</p><p><a href="https://juejin.cn/post/6976903535191392270" target="_blank" rel="noopener noreferrer">React Hooks 核心实现</a></p><p><a href="https://www.yuque.com/liangxinchao/react/qimukg" target="_blank" rel="noopener noreferrer">深入浅出 React</a></p><p><a href="https://react.iamkasong.com/process/fiber-mental.html#%E4%BB%80%E4%B9%88%E6%98%AF%E4%BB%A3%E6%95%B0%E6%95%88%E5%BA%94" target="_blank" rel="noopener noreferrer">React 技术揭秘</a></p><p>📒 React 17 架构</p><p><a href="https://github.com/7kms/react-illustration-series/tree/v17.0.1" target="_blank" rel="noopener noreferrer">图解 React 原理系列</a></p><p><a href="https://react.iamkasong.com/preparation/newConstructure.html" target="_blank" rel="noopener noreferrer">React16架构</a></p><p>📒 数组的 <code>flatMap</code> 方法</p><p>数组的 <code>[].map()</code> 可以实现一对一的映射，映射后的数组长度与原数组相同。有时候需要过滤掉一些元素，或者实现一对多的映射，这时候只用 <code>map</code> 就无法实现了。这种情况下就可以使用 <code>flatMap</code>：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 需要过滤掉 0，并且使其余各元素的值翻倍</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> numbers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">6</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 常规方法是 map 和 filter 搭配</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> doubled </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> numbers</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">n</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> n </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">n</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> n </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用 flatMap 实现</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> doubled </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> numbers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">flatMap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">number</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> number </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> number</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>此外还可以实现一对多的映射：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> numbers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> trippled </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> numbers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">flatMap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">number</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> number</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">trippled</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// [1, 2, 3, 4, 8, 12]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p><code>flatMap</code> 实际上是先 <code>map</code> 再 <code>flat</code>，理解了这一点就能掌握了</p></div></div><p>📒 <a href="https://blog.appsignal.com/2022/01/19/how-to-set-up-a-nodejs-project-with-typescript.html" target="_blank" rel="noopener noreferrer">如何用 TypeScript 配置一个 Node 项目</a></p><p>📒 <a href="https://remix.run/blog/remix-vs-next" target="_blank" rel="noopener noreferrer">Remix vs Next.js</a></p><p>📒 <a href="https://blog.openreplay.com/3-react-component-design-patterns-you-should-know-about/" target="_blank" rel="noopener noreferrer">你应该知道的三个 React 组件设计模式</a></p><p>📒 <a href="https://juejin.cn/post/7055202073511460895" target="_blank" rel="noopener noreferrer">V8 Promise源码全面解读，其实你对Promise一无所知</a></p><p>⭐️ <a href="https://juejin.cn/post/7036162494573838367" target="_blank" rel="noopener noreferrer">60+ 实用 React 工具库，助力你高效开发！</a></p><p>⭐️ 如何编写更好的 JSX 语句</p><details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>查看详情</summary><div><div class="collapsibleContent_i85q"><p>列表不为空的时候进行渲染：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 注意这种写法有 bug</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 如果 data 数组为空，则会直接渲染 `0` 到页面上</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">d</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> d</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用 &amp;&amp; 的时候需要手动转换布尔值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> jsx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">!</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> jsx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token known-class-name class-name">Boolean</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> jsx</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>不要使用 <code>props</code> 传递的 React 元素作为判断条件:</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 这样的判断不准确</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// props.children 可能是一个空数组 []</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用 children.length 也不严谨，因为 children 也可能是单个元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用 React.Children.count(props.children) 支持单个和多个 children</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 但是对于存在多个无效节点，例如 false 无法准确判断</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 使用 React.Children.toArray(props.children) 可以删除无效节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 但是对于一个空片段，例如 &lt;&gt;&lt;/&gt; 又会被识别为有效的元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 所以为了避免出错，建议不要这样判断</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name" style="color:#d73a49">Wrap</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">children</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">props</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">children</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>重新挂载还是更新：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 使用三元运算符分支编写的 JSX 看上去就像完全独立的代码</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">hasItem </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Item</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript number" style="color:#36acaa">1</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Item</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript number" style="color:#36acaa">2</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 但实际上 hasItem 切换时，React 仍然会保留挂载的实例，然后更新 props</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 因此上面的代码实际上等价于下面这样</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Item</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">hasItem </span><span class="token tag script language-javascript operator" style="color:#393A34">?</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript number" style="color:#36acaa">1</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript number" style="color:#36acaa">2</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 一般来讲不会有什么问题，但是对于非受控组件，就可能导致 bug</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 例如 mode 属性变化，会发现之前输入的信息还在</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">mode </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'name'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">name</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">phone</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 由于 React 会尽可能复用组件实例</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 因此我们可以传递 key，告诉 React 这是两个完全不一样的元素，让 React 强制重新渲染</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">mode </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'name'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">name</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">name</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">phone</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">phone</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 或者使用 &amp;&amp; 替代三元运算符</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">mode </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'name'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> input  placeholder </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"name"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">mode </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'name'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> input  placeholder </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"phone"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 相反，如果在同一个元素上的逻辑条件不太一样</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 可以试着将条件拆分为两个单独的 JSX 提高可读性</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">  </span><span class="token tag attr-name" style="color:#00a4db">aria-busy</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">loading</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">  </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">loading </span><span class="token tag script language-javascript operator" style="color:#393A34">?</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript keyword null nil" style="color:#00009f">null</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> submit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f"></span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">loading </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Spinner</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'submit'</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 可以改为下面这样</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">loading</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">aria-busy</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Spinner</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">submit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">submit</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 或者使用 &amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">loading </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">aria-busy</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Spinner</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">loading </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">key</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">submit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">submit</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://mp.weixin.qq.com/s/1BX5xK0wpUDBSininJbYHw" target="_blank" rel="noopener noreferrer">写好 JSX 条件语句的几个建议</a></p></div></div></details><p>📒 <a href="https://www.youtube.com/watch?v=M3BM9TB-8yA" target="_blank" rel="noopener noreferrer">Node.js 十大设计缺陷 - Ryan Dahl - JSConf EU</a></p><p>📒 <a href="https://juejin.cn/post/7056612950412361741" target="_blank" rel="noopener noreferrer">为什么说 WebAssembly 是 Web 的未来？</a></p><p>📒 <a href="https://juejin.cn/post/7047329886502912030" target="_blank" rel="noopener noreferrer">浅析TypeScript Compiler 原理</a></p><p>📒 <a href="https://juejin.cn/post/7056018952098414605" target="_blank" rel="noopener noreferrer">TypeScript 4.6 beta 发布：递归类型检查增强、参数的控制流分析支持、索引访问的类型推导</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[1月23日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月23日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月23日内容汇总"/>
        <updated>2022-01-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Golang 如何根据指针访问对应的值]]></summary>
        <content type="html"><![CDATA[<p>📒 Golang 如何根据指针访问对应的值</p><p>原始类型需要手动使用 <code>*</code> 操作符，复杂对象会自动解除指针引用：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">num </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token number" style="color:#36acaa">42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 打印的是内存地址</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ms </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">myStruct</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">ms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">17</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">ms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 17</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 对于复杂对象，直接操作就行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ms</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">17</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ms</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 17</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Golang 创建对象指针的三种方式</p><p>Golang 中所有的赋值操作都是 copy，例如原始类型、<code>array</code>、<code>struct</code>，有两种例外：<code>map</code> 和 <code>slice</code>，它们具有内部指针，在赋值的时候传递指针类型。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 第一种：对已有的值类型使用 `&amp;` 操作符</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ms </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> myStruct</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">ms</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 第二种：在初始化的时候使用 `&amp;` 操作符</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">p </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">myStruct</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">foo</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 第三种：使用 `new` 关键字，这种方法不能在初始化的时候进行赋值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> ms </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">myStruct </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">myStruct</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 如何渲染虚拟 DOM</p><p>所谓虚拟 DOM 其实就是一棵多叉树，可以使用下面的结构表示：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">VDOM</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ElementTagName</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  props</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ElementProps</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  children</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">VDOM</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>渲染虚拟 DOM，很明显要用递归，对不同的类型做不同的处理：</p><ul><li>如果是文本类型，就要用 <code>document.createTextNode</code> 创建文本节点；</li><li>如果是元素类型，就要用 <code>document.createElement</code> 创建元素节点，元素节点还有属性要处理，并且要递归渲染子节点；</li></ul><p>实现 <code>render</code> 函数如下：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">vdom</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> parent </span><span class="token parameter operator" style="color:#393A34">=</span><span class="token parameter"> </span><span class="token parameter keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">mount</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">el</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">parent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> el</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 如有父节点则挂载到父节点，组装为 DOM 树</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> parent</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">appendChild</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">el</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">isTextVdom</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vdom</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 创建文本节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">mount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createTextNode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vdom</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">isElementVdom</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vdom</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 创建元素节点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> dom </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">mount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createElement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vdom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">type</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 递归渲染子节点，这里使用深度优先遍历</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> child </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> vdom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">children</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">child</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> dom</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 给元素添加属性</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> prop </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> vdom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">props</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token function" style="color:#d73a49">setAttribute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dom</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> prop</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> vdom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">props</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">prop</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> dom</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如何判断文本节点：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isTextVdom</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">vdom</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> vdom </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'string'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> vdom </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'number'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如何判断元素节点：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isElementVdom</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">vdom</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> vdom </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'object'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> vdom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">type</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'string'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如何处理样式、事件、属性：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">setAttribute</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">dom</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> key</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'function'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">startsWith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'on'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 事件处理，使用 `addEventListener` 设置</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> eventType </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toLowerCase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    dom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">eventType</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'style'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'object'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 样式处理，合并样式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">style</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'object'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'function'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 属性处理，使用 `setAttribute` 设置</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    dom</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">setAttribute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/7054034318594850823" target="_blank" rel="noopener noreferrer">能用js实现的最终用js实现，Shell脚本也不例外</a></p><p>📒 <a href="https://github.com/luciopaiva/heapify" target="_blank" rel="noopener noreferrer">heapify：最快的 JavaScript 优先级队列库</a></p><p>📒 <a href="https://github.com/mailru/easyjson" target="_blank" rel="noopener noreferrer">easyjson：Golang 中的序列化库，比 <code>encoding/json</code> 快 4-5 倍</a></p><p>📒 <a href="https://github.com/fastify/fast-json-stringify" target="_blank" rel="noopener noreferrer">fast-json-stringify：比 <code>JSON.stringify</code> 快两倍</a></p><p>📒 <a href="https://juejin.cn/post/7048970987500470279" target="_blank" rel="noopener noreferrer">六千字详解！vue3 响应式是如何实现的？</a></p><p>📒 Nodejs 如何将图片转为 base64</p><p>使用 Buffer 对象：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">fs</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node:fs"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">path</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node:path"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> raw </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">readFileSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./2333.png'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'binary'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> buf </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">Buffer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">raw</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'binary'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> string </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> buf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'base64'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>同理可以将 base64 转回图片：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> raw </span><span class="token operator" style="color:#393A34">=</span><span class="token plain">  </span><span class="token maybe-class-name">Buffer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'base64'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'binary'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Nodejs 如何实现图片处理</p><p>推荐使用 <code>sharp</code> 这个库，可以实现图片压缩，转 JPEG、PNG、WebP 等格式：</p><blockquote><p><a href="https://github.com/lovell/sharp" target="_blank" rel="noopener noreferrer">https://github.com/lovell/sharp</a></p></blockquote><p>📒 如何打印 26 个字母的字符串</p><p>一行代码搞定：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token known-class-name class-name">String</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">fromCharCode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token spread operator" style="color:#393A34">...</span><span class="token known-class-name class-name">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword module" style="color:#00009f">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">length</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">26</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">_</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">97</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 'abcdefghijklmnopqrstuvwxyz'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 如何用 Map 实现 Set</p><p>关于 Map 和 Set 是两个抽象数据结构，Map 存储一个键值对集合，其中键不重复，Set 存储一个不重复的元素集合。本质上 Set 可以视为一种特殊的 Map，Set 其实就是 Map 中的键：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">NewSet</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> </span><span class="token class-name builtin">unknown</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> collection</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Map</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undefined</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">iterable</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">collection </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      iterable</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">it </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">it</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 方法重载与参数默认值</p><p>为了支持可变参数，在 Java 中通过 <strong>方法重载</strong> 实现，通过定义多个方法签名，根据实际调用传递的参数去匹配签名。在 TypeScript 中也提供了方法重载特性，但在开发中很少用到，一般都通过 <strong>参数默认值</strong> 实现可变参数：</p><div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">NewSet</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">iterable</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>注意使用参数默认值之后，TS 会自动将这个参数推导为可变参数，例如上面这个会推导为 <code>NewSet&lt;T&gt;(iterable?: T[]): void</code></p></blockquote><p>📒 项目常用工具库</p><ul><li><code>dayjs</code>：与 <code>moment</code> 的 API 设计保持一样，但体积仅有 2KB；</li><li><code>qs</code>：解析 URL query 参数的库；</li><li><code>js-cookie</code>：简单、轻量的处理 cookie 的库；</li><li><code>flv.js</code>：bilibili 开源的 HTML5 flash 播放器，使浏览器在不借助 flash 插件的情况下可以播放 flv；</li><li><code>vConsole</code>：一个轻量、可拓展、针对手机网页的前端开发者调试面板；</li><li><code>animate.css</code>：一个跨浏览器的 css3 动画库，内置了很多典型的 css3 动画，兼容性好，使用方便；</li><li><code>lodash</code>：一个一致性、模块化、高性能的 JavaScript 实用工具库；</li></ul><p>⭐️ <a href="https://github.com/ngneat/elf" target="_blank" rel="noopener noreferrer">elf: 使用 RxJs 的响应式状态管理</a></p><p>📒 如何防止 CSS 样式污染</p><ul><li>使用命名约定</li><li>CSS Modules</li><li>CSS in JS</li></ul><p>其中命名约定最流行的方式是 BEM 101。它代表了 <code>Block</code>、<code>Element</code>、<code>Modifier</code> 方法。</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[block]__[element]--[modifier]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/* Example */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token selector class" style="color:#00009f">.menu__link--blue</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/7040849488998563848" target="_blank" rel="noopener noreferrer">现代配置指南——YAML 比 JSON 高级在哪？</a></p><p>📒 <a href="https://juejin.cn/post/7029512357428592648" target="_blank" rel="noopener noreferrer">前端架构师神技，三招统一团队代码风格</a></p><p>📒 <a href="https://juejin.cn/post/7024043015794589727" target="_blank" rel="noopener noreferrer">前端架构师的 git 功力，你有几成火候？</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="git" term="git"/>
        <category label="ESLint" term="ESLint"/>
        <category label="Prettier" term="Prettier"/>
        <category label="yaml" term="yaml"/>
        <category label="CSS" term="CSS"/>
        <category label="Vue3" term="Vue3"/>
        <category label="JSON 序列化" term="JSON 序列化"/>
        <category label="Golang" term="Golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[1月16日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月16日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月16日内容汇总"/>
        <updated>2022-01-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 实现一个 WebAssembily 版本的 Python 解释器]]></summary>
        <content type="html"><![CDATA[<p>📒 实现一个 WebAssembily 版本的 Python 解释器</p><ul><li>wasm 可以把代码编译出来，但是能否执行</li><li>如果 Python 代码涉及系统调用，例如代码中经常需要进行文件 IO，这种情况下 wasm 能否实现</li></ul><blockquote><p><a href="https://github.com/pyodide/pyodide" target="_blank" rel="noopener noreferrer">https://github.com/pyodide/pyodide</a></p></blockquote><p>📒 Webpack5 配置了 <code>devServer.hot = true</code> 是否会自动配置 <code>HotModuleReplacementPlugin</code></p><p>📒 看下 axios 源码，响应拦截中第一个回调 <code>reject</code> 能否进入第二个回调</p><p>📒 webpack-dev-server 如何配置代理</p><details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>查看详情</summary><div><div class="collapsibleContent_i85q"><p>在 CRA 搭建的项目中，我们知道可以在 <code>src/setupProxy.js</code> 文件中写入代理配置：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> proxy </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'http-proxy-middleware'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">app</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">use</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">proxy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'/course'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">target</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'https://ke.study.163.com'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">changeOrigin</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>那么手动搭建的项目该如何配置代理呢？我们看一下 CRA 源码：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// react-scripts/config/paths.js:87</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">proxySetup</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">resolveApp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'src/setupProxy.js'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>然后去找哪里用到了 <code>proxySetup</code> ：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// react-scripts/config/webpackDevServer.config.js:112</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">onBeforeSetupMiddleware</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">devServer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Keep `evalSourceMapMiddleware`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// middlewares before `redirectServedPath` otherwise will not have any effect</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// This lets us fetch source contents from webpack for the error overlay</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  devServer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">use</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">evalSourceMapMiddleware</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">devServer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">existsSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paths</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">proxySetup</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// This registers user provided middleware for proxy reasons</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paths</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">proxySetup</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">devServer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">app</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>看了下上面的配置，说明应该是这么用的：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> compiler </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">webpack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> devServer </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">WebpackDevServer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> compiler</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">devServer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">use</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">proxy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">'/course'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">target</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'https://ke.study.163.com'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">changeOrigin</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></details><p>📒 <a href="https://juejin.cn/post/7051535411042058271" target="_blank" rel="noopener noreferrer">不优雅的 React Hooks</a></p><p>📒 为什么可以用函数模拟一个模块</p><p>在一个模块中，有一些属性和方法是私有的，另外一些是对外暴露的：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// main.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> bar </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">getFoo</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> foo</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">getBar</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> bar</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">defaultExport</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> bar</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> defaultExport</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// index.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">main</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> getFoo</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> getBar </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./main"</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这种行为就可以通过函数模拟出来，其中私有变量、方法以闭包的形式实现，这样只有模块内部才能访问：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> main </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> bar </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">getFoo</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> foo</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">getBar</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> bar</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">defaultExport</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> foo </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> bar</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    getFoo</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    getBar</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword module" style="color:#00009f">default</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> defaultExport</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>可以看到给默认导出加了一个 <code>deafult</code> 属性。</p></div></div><p>另外推荐看看 <code>browserify</code> 这个库，如何在浏览器端实现 CommonJS 模块机制：</p><blockquote><p><a href="https://browserify.org/" target="_blank" rel="noopener noreferrer">https://browserify.org/</a></p></blockquote><p>📒 Webpack 中 loader 处理流程</p><p>有点像责任链模式，上一个函数的返回值会作为参数传入下一个函数。需要注意使用 <code>call</code> 方法让每个 loader 内部可以获取到 loaderAPI：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> readFileSync </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'node:fs'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> loaders </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> raw </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">readFileSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'xxx'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> loaderAPI </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">emitFile</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> parsed </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> loaders</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">accu</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> cur</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> cur</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">loaderAPI</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> accu</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  raw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 字体文件的 hash 是如何生成的，<code>file-loader</code> 中如何处理的</p><p>写一篇文章：《你不知道的 Webpack loader —— file-loader 源码探秘》</p><p><a href="https://www.cnblogs.com/shiyunfront/articles/8944940.html" target="_blank" rel="noopener noreferrer">webpack 源码解析:file-loader 和 url-loader</a></p><p><a href="https://github.com/webpack-contrib/file-loader/blob/master/src/index.js" target="_blank" rel="noopener noreferrer">file-loader - GitHub</a></p><p><a href="https://github.com/webpack/loader-utils/blob/master/lib/interpolateName.js" target="_blank" rel="noopener noreferrer">loader-utils - GitHub</a></p><p>📒 Golang 编译为 WebAssembly</p><p>在 Golang 中可以使用 <code>syscall/js</code> 这个库与 JS 环境进行交互，可以调用 JS 的 API，以及传递 JSON 数据：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">package</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"encoding/json"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"fmt"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"syscall/js"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Person </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Name </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">`json:"name"`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Age  </span><span class="token builtin">int</span><span class="token plain">    </span><span class="token string" style="color:#e3116c">`json:"age"`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Work around for passing structs to JS</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  frank </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">Person</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Frank"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Age</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">28</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  p</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Marshal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frank</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  obj </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> js</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Global</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"JSON"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"parse"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  js</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Global</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"aObject"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> obj</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://www.sitepen.com/blog/compiling-go-to-webassembly" target="_blank" rel="noopener noreferrer">Compiling Go to WebAssembly</a></p><p>📒 Golang 中的指针</p><p>对于原始类型来说，赋值就等于 copy，相当于在内存中创建一个一模一样的值，具有不同的内存地址：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  a </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  b </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> a</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 42 42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">27</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 27 42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>可以通过 <code>&amp;</code> 操作符取到内存地址：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> a </span><span class="token builtin">int</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">*</span><span class="token builtin">int</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 42 0×1040a124</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>还可以通过 <code>*</code> 操作符根据内存地址访问对应的值：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> a </span><span class="token builtin">int</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">*</span><span class="token builtin">int</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 42 42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>由于 <code>b</code> 实际持有的是 <code>a</code> 的指针引用，因此修改 <code>a</code> 会导致 <code>b</code> 指向的值发生变化：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> a </span><span class="token builtin">int</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">*</span><span class="token builtin">int</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">a</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 42 42</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">27</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 27 27</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">14</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 14 14</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 Golang 中的 <code>struct</code></p><p>注意 <code>struct</code> 与 <code>slice</code>、<code>map</code> 不同，下面这个操作实际上是完整 copy 了一个对象，内存开销较大：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">package</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">"fmt"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Doctor </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  aDoctor </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> Doctor</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"John Pertwee"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  anotherDoctor </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> aDoctor</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  anotherDoctor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Tom Baker"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">aDoctor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// {John Pertwee}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">anotherDoctor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// {Tom Baker}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>可以使用 <code>&amp;</code> 操作符拿到对象的指针进行赋值，这时候两边就是联动的：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  aDoctor </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> Doctor</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"John Pertwee"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  anotherDoctor </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">aDoctor</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  anotherDoctor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Tom Baker"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">aDoctor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// {Tom Baker}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">anotherDoctor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// &amp;{Tom Baker}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>注意 <code>array</code> 进行赋值也会 copy：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  a </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">{</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  b </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> a</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// [1, 2, 3] [1, 2, 3]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  a</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// [1, 42, 3] [1, 2, 3]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>但如果将 <code>array</code> 改为 <code>slice</code>，赋值传递的就是指针：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  a </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">{</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  b </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> a</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// [1, 2, 3] [1, 2, 3]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  a</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// [1, 2, 3] [1, 2, 3]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>📒 <a href="https://juejin.cn/post/7051929587852247077" target="_blank" rel="noopener noreferrer">年终盘点：2022基于Monorepo的首个大趋势-TurboRepo</a></p><p>⭐️ <a href="https://juejin.cn/post/7034419410706104356" target="_blank" rel="noopener noreferrer">2022年如何成为一名优秀的大前端Leader？</a></p><p>📒 GitHub 定时任务</p><p>下面的代码中，<code>on</code> 字段指定了两种触发条件，一个是代码 <code>push</code> 进仓库，另一种是定时任务，每天在国际标准时间21点（北京时间早上5点）运行。</p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">on</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">push</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">schedule</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">cron</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'0 21 * * *'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>定时任务配置参考：</p><blockquote><p><a href="https://github.com/lxchuan12/juejin-actions" target="_blank" rel="noopener noreferrer">https://github.com/lxchuan12/juejin-actions</a></p></blockquote><p>另外推荐一个项目，可以使用 <code>curl wttr.in</code> 命令获取天气预报：</p><blockquote><p><a href="https://github.com/chubin/wttr.in" target="_blank" rel="noopener noreferrer">https://github.com/chubin/wttr.in</a></p></blockquote><p>📒 如何开发一个 CLI 工具</p><p>参考下尤大的项目：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> templateDir </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">template-</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">template</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">write</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">file</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> targetPath </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> renameFiles</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">file</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> renameFiles</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">file</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> file</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">writeFileSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">targetPath</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">copy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">templateDir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> file</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> targetPath</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> files </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">readdirSync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">templateDir</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> file </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> files</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> f </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'package.json'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">file</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>注意这里有两个文件要处理下，一个是给 <code>package.json</code> 修改包名：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> pkg </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">templateDir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">package.json</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pkg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> packageName </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> targetDir</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'package.json'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">stringify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pkg</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword null nil" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>还有是 <code>.gitignore</code> 修改文件名：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> renameFiles </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">_gitignore</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'.gitignore'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://github.com/vitejs/vite/blob/main/packages/create-vite/index.js" target="_blank" rel="noopener noreferrer">https://github.com/vitejs/vite/blob/main/packages/create-vite/index.js</a></p></blockquote><p>📒 命令行工具开发技术栈</p><ul><li><code>chalk/kolorist</code></li><li><code>inquirer/prompts</code></li><li><code>ora</code></li><li><code>semver</code></li><li><code>pkg-install</code></li><li><code>ncp</code></li><li><code>commander/yargs</code></li><li><code>execa</code>（个人觉得 Node 原生 <code>child_process</code> 的 <code>exec</code> 就够用了）</li><li><code>minimist</code></li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>网上一些文章也都实现了递归拷贝文件，但是是否考虑到了跨平台，可以看下 <code>ncp</code> 的实现</p><p><a href="https://github.com/AvianFlu/ncp" target="_blank" rel="noopener noreferrer">https://github.com/AvianFlu/ncp</a></p><p>Node.js 原生的 <code>child_process.exec</code> 也可以执行命令，看下 <code>execa</code> 是如何支持 Promise 的</p><p><a href="https://github.com/sindresorhus/execa" target="_blank" rel="noopener noreferrer">https://github.com/sindresorhus/execa</a></p></div></div><p>现在开发已经不需要自己组装 pick 了，<code>common-bin</code>、<code>oclif</code> 这两个，约定式路由。</p><p>另外脚手架工具，可以看看 <code>plop</code>和 <code>yeoman</code>，一个是基于 <code>action</code> 和 <code>inquirer</code> 的生态，一个是内核加自定义模板项目。</p><p>其实最简单的脚手架，不是通过cli界面选择模板，然后到 github 上去下载对应的模板文件，而是 <code>start-kit</code> 。</p><blockquote><p><a href="https://github.com/digipolisantwerp/starter-kit-ui_app_nodejs" target="_blank" rel="noopener noreferrer">https://github.com/digipolisantwerp/starter-kit-ui_app_nodejs</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7051355444341637128" target="_blank" rel="noopener noreferrer">「前端基建」探索不同项目场景下Babel最佳实践方案</a></p><p>📒 <a href="https://juejin.cn/post/7051236803344334862" target="_blank" rel="noopener noreferrer">说不清rollup能输出哪6种格式😥差点被鄙视</a></p><p>📒 <a href="https://juejin.cn/post/7035448197883363359" target="_blank" rel="noopener noreferrer">【手把手】学会VS Code"任务"神技，成为项目组最靓的崽！</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="Babel" term="Babel"/>
        <category label="Rollup" term="Rollup"/>
        <category label="VS Code" term="VS Code"/>
        <category label="命令行工具" term="命令行工具"/>
        <category label="CLI 工具" term="CLI 工具"/>
        <category label="GitHub 定时任务" term="GitHub 定时任务"/>
        <category label="Golang" term="Golang"/>
        <category label="Webpack loader" term="Webpack loader"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[1月9日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月9日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月9日内容汇总"/>
        <updated>2022-01-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 Golang 模拟 JS 的 Promise]]></summary>
        <content type="html"><![CDATA[<p>📒 Golang 模拟 JS 的 Promise</p><p><a href="https://www.bilibili.com/video/BV11v411h7t5" target="_blank" rel="noopener noreferrer">https://www.bilibili.com/video/BV11v411h7t5</a></p><p>📒 Golang 如何通过 WebAssembly 调用 JS API</p><p><a href="https://github.com/elliotforbes/go-webassembly-framework" target="_blank" rel="noopener noreferrer">https://github.com/elliotforbes/go-webassembly-framework</a></p><p>📒 <a href="https://juejin.cn/post/7039850183244382216" target="_blank" rel="noopener noreferrer">「目前全网唯一&amp;2万字长文」从JS上下文到Chromium源码的极限拉扯！!兄弟姐妹们接好了！！</a></p><p>📒 <a href="https://juejin.cn/post/6932367804108800007" target="_blank" rel="noopener noreferrer">浅谈 Vite 2.0 原理，依赖预编译，插件机制是如何兼容 Rollup 的？</a></p><p>📒 JS 两个注意点</p><ul><li><p>判断对象是否存在某属性，通常都用 <code>Object.prototype.hasOwnProperty.call()</code>。有同学问为什么不能直接 <code>obj.hasOwnProperty()</code> 去判断，因为有些对象是通过 <code>Object.create(null)</code> 创建的，这种情况下原型上就访问不到 <code>hasOwnProperty</code>，必须通过 <code>Object.prototype.hasOwnProperty.call()</code></p></li><li><p>ES2016 新增的 <code>Array.prototype.includes()</code> 可以识别 <code>NaN</code>，而 <code>Array.prototype.indexOf()</code> 不能识别：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> arr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'es6'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'es7'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">NaN</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'es8'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">includes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">NaN</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">indexOf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">NaN</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// -1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ul><p>📒 今年最受欢迎的项目：谷歌的 <strong>zx</strong></p><p>使用 zx 可以编写简单的命令行脚本：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token hashbang comment" style="color:#999988;font-style:italic">#!/usr/bin/env zx</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> $</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">cat package.json | grep name</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> branch </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> $</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">git branch --show-current</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> $</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">dep deploy --branch=</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">branch</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> </span><span class="token known-class-name class-name">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">sleep 1; echo 1</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">sleep 2; echo 2</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  $</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">sleep 3; echo 3</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'foo bar'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> $</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">mkdir /tmp/</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>zx 涵盖了多个软件包提供的功能：</p><ul><li><code>node-fetch</code>：使用与浏览器中相同的 API 发出 HTTP 请求</li><li><code>fs-extra</code>：运行文件系统</li></ul><p>这块源码不是很多，推荐看一下：</p><p><a href="https://github.com/google/zx" target="_blank" rel="noopener noreferrer">https://github.com/google/zx</a></p><p>📒 工程化方案总结下</p><p><a href="https://zhuanlan.zhihu.com/p/403970666" target="_blank" rel="noopener noreferrer">2021 年 TypeScript + React 工程化指南</a></p><p><a href="https://juejin.cn/post/7017710911443959839" target="_blank" rel="noopener noreferrer">2021 年当我们聊前端部署时，我们在聊什么</a></p><p>📒 TypeScript 类型体操</p><p><a href="https://mp.weixin.qq.com/s/-x8iVK-hlQd3-OZDC04A5A" target="_blank" rel="noopener noreferrer">TypeScript 类型编程: 从基础到编译器实战</a></p><p><a href="https://juejin.cn/post/7050099282317148174" target="_blank" rel="noopener noreferrer">知其然，知其所以然：TypeScript 中的协变与逆变</a></p><p>📒 monorepo 项目</p><p><a href="https://juejin.cn/post/7043998041786810398" target="_blank" rel="noopener noreferrer">One For All：基于pnpm + lerna + typescript的最佳项目实践 - 理论篇</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/Yo-W7CbkOrBMSfK75qrAhg" target="_blank" rel="noopener noreferrer">漫画图解 Chrome 浏览器从输入到渲染的原理（7000 字）</a></p><p>📒 QUIC 协议</p><p>推荐看看 QUIC 101 视频以及 <a href="https://courses.cs.washington.edu/courses/cse550/20au/papers/CSE550.quic.pdf" target="_blank" rel="noopener noreferrer">The QUIC transport protocol: design and Internet-scale deployment</a> 论文</p><p>📒 ES2015+ 的代码要不要转为 ES5</p><p>Babel 主要做了两件事，一是语法转换，二是 api 兼容，其中 api 兼容是通过引入 core-js 的 polyfill 实现的。一般来说转换之后体积肯定会增大，并且很多语法转换的时候会引入 helper 函数，这就产生了副作用，导致无法 Tree-Shaking。</p><p><a href="https://juejin.cn/post/7049696761858195486" target="_blank" rel="noopener noreferrer">ES6 以上版本代码要不要转码成 ES5?</a></p><p>📒 如何覆盖 CRA 默认 webpack 配置</p><details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>查看详情</summary><div><div class="collapsibleContent_i85q"><p>在 CRA 创建的项目中，经常需要修改默认 webpack 配置。但是 CRA 不像 Vue-cli 可以提供自定义 webpack 配置，而 <code>eject</code> 又会把全部配置暴露出来，很麻烦。这种情况下可以使用 <code>react-app-rewired</code> 这个库：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">yarn</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> react-app-rewired -D</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在项目根目录创建一个 <code>config-overrides.js</code> 文件，添加自定义 webpack 配置：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/* config-overrides.js */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">override</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">config</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> env</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">//do stuff with the webpack config...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>最后在 <code>package.json</code> 中修改 npm scripts：</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/* package.json */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-   </span><span class="token property" style="color:#36acaa">"start"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-scripts start"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">+   </span><span class="token property" style="color:#36acaa">"start"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-app-rewired start"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-   </span><span class="token property" style="color:#36acaa">"build"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-scripts build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">+   </span><span class="token property" style="color:#36acaa">"build"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-app-rewired build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-   </span><span class="token property" style="color:#36acaa">"test"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-scripts test"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">+   </span><span class="token property" style="color:#36acaa">"test"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-app-rewired test"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"eject"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react-scripts eject"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这个库源码不是很多，推荐看一下：</p><p><a href="https://github.com/timarney/react-app-rewired" target="_blank" rel="noopener noreferrer">https://github.com/timarney/react-app-rewired</a></p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>通常 <code>react-app-rewired</code> 会搭配 <code>customize-cra</code> 这个库一起用：</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">yarn</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> customize-cra react-app-rewired -D</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>支持在 <code>config-overrides.js</code> 中编写函数式的 API 去修改 webpack 配置：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  override</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  addDecoratorsLegacy</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  disableEsLint</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  addWebpackAlias</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"customize-cra"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> path </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">override</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// enable legacy decorators babel plugin</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">addDecoratorsLegacy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// disable eslint in webpack</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">disableEsLint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// add an alias for "ag-grid-react" imports</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">addWebpackAlias</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"ag-grid-react$"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">__dirname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"src/shared/agGridWrapper.js"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://github.com/arackaf/customize-cra" target="_blank" rel="noopener noreferrer">https://github.com/arackaf/customize-cra</a></p></div></div></div></div></details><p>📒 React 组件懒加载实现思路</p><p>项目中经常需要长列表渲染，一般都使用懒加载，滚动到底部时渲染下一屏数据，需要判断元素是否在 viewport 内。过去通常会监听滚动事件，然后调用 <code>Element.getBoundingClientRect()</code> 方法以获取元素的边界信息。由于滚动事件触发非常频繁，频繁调用会导致性能问题。</p><p>这种情况下可以使用 <code>Intersection Observer API</code>，仅在被监听元素进入或者退出 viewport 时触发回调，这样就不会大量占用主线程。</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> observer </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">IntersectionObserver</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">callback</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> target </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">document</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">querySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'#listItem'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">observer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">observe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">target</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>在 React 项目中，还可以使用 <code>react-intersection-observer</code> 这个库。</p><p><a href="https://www.npmjs.com/package/react-intersection-observer/v/8.28.3" target="_blank" rel="noopener noreferrer">react-intersection-observer - npm</a></p></div></div><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API" target="_blank" rel="noopener noreferrer">Intersection Observer API - MDN</a></p><p><a href="https://juejin.cn/post/6955287500311150605" target="_blank" rel="noopener noreferrer">懒加载 React 长页面 - 动态渲染组件</a></p><p>📒 <a href="https://mp.weixin.qq.com/s/RCBHBtAFaeR6wqsyuGI_hQ" target="_blank" rel="noopener noreferrer">如何避免 React 组件重复渲染</a></p><p>📒 React 16 架构</p><p>React16架构可以分为三层：</p><ul><li>Scheduler（调度器）—— 核心职责只有 1 个, 就是执行回调。把react-reconciler提供的回调函数, 包装到一个任务对象中.在内部维护一个任务队列, 优先级高的排在最前面。循环消费任务队列, 直到队列清空</li><li>Reconciler（协调器）—— 负责找出变化的组件，16版本主要是Fiber，15版本是stack。区别在于增加了优先级系统，通过遍历的方式实现可中断的递归，将fiber树的构造过程包装在一个回调函数中, 并将此回调函数传入到scheduler包等待调度</li><li>Renderer（渲染器）—— 负责将变化的组件渲染到页面上，能够将react-reconciler包构造出来的fiber树表现出来, 生成 dom 节点(浏览器中), 生成字符串(ssr)，比如说react-dom、react-native。
所以react-native的作用主要是将react提供的节点，渲染到app页面上</li></ul><p>我们书写的react-native组件，比如说View、Text等，需要通过react-native-web来变成react-dom可以识别的节点</p><p>📒 如何在 JB 全家桶中使用 VS Code 的快捷键</p><details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>查看详情</summary><div><div class="collapsibleContent_i85q"><p>JB 全家桶，例如 IDEA、WebStorm、GoLand 等支持多种 keymap，如要使用 VS Code 的快捷键，只需要安装对应的 Keymap 即可：</p><div class="image-wrapper"><div class="ant-image"><img class="ant-image-img"><div class="ant-image-mask"><div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg viewBox="64 64 896 896" focusable="false" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div></div></div></div><p>安装后应用即可：</p><div class="image-wrapper"><div class="ant-image"><img class="ant-image-img"><div class="ant-image-mask"><div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg viewBox="64 64 896 896" focusable="false" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div></div></div></div><p>同理主题也可以安装，在 JB 全家桶中推荐使用 One Dark Theme，安装完成后点击 apply 即可：</p><div class="image-wrapper"><div class="ant-image"><img class="ant-image-img"><div class="ant-image-mask"><div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg viewBox="64 64 896 896" focusable="false" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div></div></div></div></div></div></details><p>📒 静态页面部署方案</p><p><a href="https://juejin.cn/post/7041870446576271368" target="_blank" rel="noopener noreferrer">一篇教你代码同步 Github 和 Gitee</a></p><p><a href="https://mp.weixin.qq.com/s/rfyqQgpylFT7slukkbi6rw" target="_blank" rel="noopener noreferrer">教你如何使用vercel服务免费部署前端项目和serverless api</a></p><p>📒 webpack 热模块替换看下源码</p><p><a href="https://juejin.cn/post/7049608872553611301" target="_blank" rel="noopener noreferrer">webpack模块热更新原理</a></p><p><a href="https://juejin.cn/post/7021729340945596424" target="_blank" rel="noopener noreferrer">Webpack 原理系列十：HMR 原理全解析</a></p><p>📒 <a href="https://juejin.cn/post/6844903942074138637" target="_blank" rel="noopener noreferrer">聊一聊前端算法面试——递归</a></p><p>📒 <a href="https://juejin.cn/post/7049293284883038238" target="_blank" rel="noopener noreferrer">前端单元测试入门与最佳实践</a></p><p>📒 <a href="https://juejin.cn/post/7049335008917454855" target="_blank" rel="noopener noreferrer">淘宝店铺的 TypeScript ESLint 规则集考量</a></p><p>📒 自动发布脚本</p><p><a href="https://github.com/release-it/release-it" target="_blank" rel="noopener noreferrer">https://github.com/release-it/release-it</a></p><p>📒 diff 算法相关</p><p><a href="https://github.com/snabbdom/snabbdom" target="_blank" rel="noopener noreferrer">https://github.com/snabbdom/snabbdom</a></p><p><a href="https://juejin.cn/post/7000266544181674014" target="_blank" rel="noopener noreferrer">DIff算法看不懂就一起来砍我(带图)</a></p><p>📒 <a href="https://juejin.cn/post/7048253632055083022" target="_blank" rel="noopener noreferrer">如何盘点出掘金的年度高赞文章？</a></p><p>📒 <a href="https://juejin.cn/post/7047705995534925832" target="_blank" rel="noopener noreferrer">盘点掘金 2021 高赞 Vue 文章</a></p><p>📒 <a href="https://juejin.cn/post/7047690546417565733" target="_blank" rel="noopener noreferrer">盘点掘金 2021 高赞 React 文章</a></p><p>📒 <a href="https://juejin.cn/post/7047153016771706916" target="_blank" rel="noopener noreferrer">盘点掘金 2021 点赞高达 6000，收藏过万的文章</a></p><p>📒 <a href="https://juejin.cn/post/7036318575165964325" target="_blank" rel="noopener noreferrer">如何测试驱动开发 React 组件？</a></p><p>📒 <a href="https://juejin.cn/post/7030250953215311908" target="_blank" rel="noopener noreferrer">一起来写 VS Code 插件:为你的团队提供常用代码片段</a></p><p>📒 黑暗模式常用换肤方案</p><p><strong>CSS Variables</strong></p><p>css variables 是 Web 标准实现了对深色模式的支持，以下代码通过 CSS 媒体查询：</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token selector pseudo-class" style="color:#00009f">:root</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">color-scheme</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> light dark</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token variable" style="color:#36acaa">--nav-bg-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token hexcode color">#F7F7F7</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token variable" style="color:#36acaa">--content-bg-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token hexcode color">#FFFFFF</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token variable" style="color:#36acaa">--font-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color function" style="color:#d73a49">rgba</span><span class="token color punctuation" style="color:#393A34">(</span><span class="token color number" style="color:#36acaa">0</span><span class="token color punctuation" style="color:#393A34">,</span><span class="token color number" style="color:#36acaa">0</span><span class="token color punctuation" style="color:#393A34">,</span><span class="token color number" style="color:#36acaa">0</span><span class="token color punctuation" style="color:#393A34">,</span><span class="token color number" style="color:#36acaa">.9</span><span class="token color punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token atrule rule" style="color:#00a4db">@media</span><span class="token atrule" style="color:#00a4db"> </span><span class="token atrule punctuation" style="color:#393A34">(</span><span class="token atrule property" style="color:#36acaa">prefers-color-scheme</span><span class="token atrule punctuation" style="color:#393A34">:</span><span class="token atrule" style="color:#00a4db"> dark</span><span class="token atrule punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token selector pseudo-class" style="color:#00009f">:root</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">--nav-bg-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token hexcode color">#2F2F2F</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">--content-bg-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token hexcode color">#2C2C2C</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">--font-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token color function" style="color:#d73a49">rgba</span><span class="token color punctuation" style="color:#393A34">(</span><span class="token color number" style="color:#36acaa">255</span><span class="token color punctuation" style="color:#393A34">,</span><span class="token color"> </span><span class="token color number" style="color:#36acaa">255</span><span class="token color punctuation" style="color:#393A34">,</span><span class="token color"> </span><span class="token color number" style="color:#36acaa">255</span><span class="token color punctuation" style="color:#393A34">,</span><span class="token color"> </span><span class="token color number" style="color:#36acaa">.8</span><span class="token color punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token selector pseudo-class" style="color:#00009f">:root</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">var</span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">--font-color</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token selector class" style="color:#00009f">.header</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">background-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">var</span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">--nav-bg-color</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token selector class" style="color:#00009f">.content</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">background-color</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">var</span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">--content-bg-color</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>优点：代码量最少，实现起来方便</p><p>缺点：存在浏览器兼容性，需要 edge16+ 才支持</p><p><strong>打包多份 css</strong></p><p>当然也可以手动打包 2 份 CSS 样式，通过动态引入样式文件进行切换。这种方式存在一个问题，当点击切换的时候会引起整个页面重排，因此我们需要单独打包出只包含颜色的样式文件。从这个思路出发，我们就接触到了 PostCSS。</p><p><a href="https://juejin.cn/post/7019580413110648863" target="_blank" rel="noopener noreferrer">使用 PostCSS 插件让你的网站支持暗黑模式</a></p><p>📒 <a href="https://juejin.cn/post/6984267680324780040" target="_blank" rel="noopener noreferrer">使用 NextJS 和 TailwindCSS 重构我的博客</a></p><p>⭐️ <a href="https://www.zhihu.com/question/493891614/answer/2269197391" target="_blank" rel="noopener noreferrer">2022 前端技术领域会有哪些新的变化？</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="工程化方案" term="工程化方案"/>
        <category label="TypeScript" term="TypeScript"/>
        <category label="monorepo" term="monorepo"/>
        <category label="QUIC" term="QUIC"/>
        <category label="CRA" term="CRA"/>
        <category label="懒加载" term="懒加载"/>
        <category label="IDEA" term="IDEA"/>
        <category label="静态页面部署" term="静态页面部署"/>
        <category label="Webpack HMR" term="Webpack HMR"/>
        <category label="Diff" term="Diff"/>
        <category label="Vue" term="Vue"/>
        <category label="React" term="React"/>
        <category label="年度高赞文章" term="年度高赞文章"/>
        <category label="VS Code" term="VS Code"/>
        <category label="黑暗模式适配" term="黑暗模式适配"/>
        <category label="PostCSS" term="PostCSS"/>
        <category label="NextJS" term="NextJS"/>
        <category label="前端技术方向" term="前端技术方向"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[1月2日内容汇总]]></title>
        <id>https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月2日内容汇总</id>
        <link href="https://frontend-weekly.oss-cn-hangzhou.aliyuncs.com/2022/1月2日内容汇总"/>
        <updated>2022-01-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[📒 clsx：classnames 的替代方案]]></summary>
        <content type="html"><![CDATA[<p>📒 <a href="https://github.com/lukeed/clsx" target="_blank" rel="noopener noreferrer">clsx：classnames 的替代方案</a></p><p>📒 TS 类型系统实现大数相加</p><p>一位数相加，总共只有 100 种情况，为了提高性能，可以选择 <strong>打表</strong> 。</p><p><a href="https://juejin.cn/post/7020663312393764871" target="_blank" rel="noopener noreferrer">用 TS 类型系统实现大数加法</a></p><p>📒 <a href="https://juejin.cn/post/7046566841522585636#heading-3" target="_blank" rel="noopener noreferrer">盘点那些让开发效率翻倍的React Hook</a></p><p>⭐️ <a href="https://mp.weixin.qq.com/s/3TKcUeoyzXvH3MGVI6Dj9A" target="_blank" rel="noopener noreferrer">ESM 与 CJS 的 Interop 来世今生</a></p><p>📒 浏览器渲染中的合成层与 <code>will-change</code></p><p>合成就是将页面的各个部分分成多个层、单独 <code>光栅化</code>（浏览器根据文档的结构、每个元素的样式、页面的几何形状和绘制顺序转换为屏幕上的像素的过程）它们并在合成器线程中合成为一个页面的技术。</p><p>一般来说，拥有一些特定属性的渲染层，会被浏览器自动提升为合成层。合成层拥有单独的图层（GraphicsLayer），和其他图层之间无不影响。而其它不是合成层的渲染层，则和第一个拥有图层的父层共用一个，也就是普通文档流中的内容，我们看一些常见的提升为合成层的属性。</p><ul><li>设置 <code>transform: translateZ(0)</code></li><li><code>backface-visibility: hidden</code> 指定当元素背面朝向观察者时是否可见</li><li><code>will-change</code> 该属性告诉浏览器该元素会有哪些变化，这样浏览器可以提前做好对应的优化准备工作</li><li><code>video</code>、<code>canvas</code>、<code>iframe</code> 等元素</li></ul><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p><strong>使用 transform 和 opacity 来实现动画</strong></p><p>在开发中经常会实现一些动画，有时候我们可能会选择改变 top/left 去实现，那么这个节点的渲染会发生在普通文档流中。而使用 <code>transform</code> 和 <code>opacity</code> 实现动画能够让节点被放置到一个独立合成层中进行渲染绘制，动画不会影响其他图层，并且 GPU 渲染相比 CPU 能够更快，这会让你的动画变的更加流畅。</p><p>按照下面的操作打开查看帧率的界面：</p><div class="image-wrapper"><div class="ant-image"><img class="ant-image-img"><div class="ant-image-mask"><div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg viewBox="64 64 896 896" focusable="false" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div></div></div></div><p>通过 <code>transform</code> 来实现动画，页面的 <code>fps</code> 能够稳定在 60 左右，而通过 <code>left</code> 来实现存在波动，<code>fps</code> 大概稳定在 30 左右，这会影响你的用户体验指标。</p></div></div><p><a href="https://juejin.cn/post/7047006440623439880" target="_blank" rel="noopener noreferrer">浏览器渲染魔法之合成层</a></p><p>⭐️ <a href="https://zhuanlan.zhihu.com/p/396010993" target="_blank" rel="noopener noreferrer">前端 Code Review 不完全指北(万字长文，50+case)</a></p><p>📒 Node.js 相关</p><p>Node.js 适合 IO 密集型任务，例如处理网络请求、文件 IO 等等；</p><p>Node.js 不适合 CPU 密集型任务，例如 MD5、SHA 加密算法等；</p><p>📒 <a href="https://segmentfault.com/a/1190000040520326" target="_blank" rel="noopener noreferrer">升级Yarn 2，摆脱node_modules</a></p><p>📒 什么是 <code>inode</code></p><p><code>inode</code> (index nodes) 是操作系统中重要的概念，是一种文件数据结构，用于存储有关除名称和数据之外的任何 Linux 文件的信息。</p><p><a href="https://juejin.cn/post/7047429181021356062" target="_blank" rel="noopener noreferrer">软链接&amp;硬链接在前端中的应用</a></p><p>📒 <a href="https://segmentfault.com/a/1190000041182817" target="_blank" rel="noopener noreferrer">gitlab上代码回滚把自己坑了后, 陷入思考🤔"bug是谁"?</a></p><p>⭐️ 提交代码的时候使用 rebase</p><p>一般提交代码都是先本地 <code>commit</code>，然后执行 <code>git pull</code> 将仓库的代码拉取到本地 merge，然后再 <code>push</code> 到仓库。这样会导致时间线很不干净，提交记录中混杂很多 merge 分支的无用记录。</p><p>在拉取仓库代码的时候，我们可以不进行合并，而是使用 rebase（变基），直接把我们原先的基础变掉，变成以别人修改过后的新代码为基础，把我们的修改在这个新的基础之上重新进行。使用变基之后，就可以使我们的时间线变得非常干净。</p><p><a href="https://segmentfault.com/a/1190000040712052" target="_blank" rel="noopener noreferrer">两条命令让你的git自动变基</a></p><p>📒 如何使用 VS Code 任务</p><p>开发经典模式：从主仓库 fork =&gt; 从个人仓库提 Merge Request</p><p><a href="https://juejin.cn/post/7035448197883363359" target="_blank" rel="noopener noreferrer">【手把手】学会VS Code"任务"神技，成为项目组最靓的崽！</a></p><p>📒 如何分析每行代码的执行耗时</p><p>首先使用 Performance 工具分析页面性能。</p><blockquote><p>在分析性能的时候，为排除插件的影响，需要启用无痕模式</p></blockquote><p>在火焰图中找到长任务，点击顶部 Task，点击 Button-Up，这时候可以看到根据耗时列出的调用栈：</p><div class="image-wrapper"><div class="ant-image"><img class="ant-image-img"><div class="ant-image-mask"><div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg viewBox="64 64 896 896" focusable="false" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div></div></div></div><p>找到那个执行耗时最长的，然后点击右侧源码地址，可以跳到 source 对应的源码：</p><div class="image-wrapper"><div class="ant-image"><img class="ant-image-img"><div class="ant-image-mask"><div class="ant-image-mask-info"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg viewBox="64 64 896 896" focusable="false" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>Preview</div></div></div></div><p>📒 关于数组遍历方法的比较</p><ul><li>相比 <code>forEach</code>，<code>map</code> 性能略差一些，因为需要创建新数组</li><li>数据量大的时候，手写 <code>for</code> 循环性能明显优于 <code>forEach</code> 和 <code>map</code><ul><li>倒序 <code>for</code> 循环性能最好，因为只访问了一次 <code>array.length</code><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 正序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 倒序</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">--</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li>如果想提升正序遍历性能，可以这样写<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> len</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">arr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">len</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li>无论遍历数组还是对象，都尽量少用 <code>for...in</code> 循环，性能比较烂</li></ul></li><li>无论 <code>new Array()</code> 还是 <code>Array.from()</code> 性能都不如写一个 <code>for</code> 循环往空数组里面 <code>push</code></li><li>另外不推荐使用 <code>[].fill()</code> 方法，TS 无法推导类型，建议使用 <code>Array.from({length: 10}, () =&gt; 1)</code> 的方式</li></ul><p>📒 如何指定一个项目所需的 node 最小版本</p><p>指定一个项目所需的 node 最小版本，这属于一个项目的质量工程。我们可以在 <code>package.json</code> 中的 <code>engines</code> 字段中指定 Node 版本号：</p><div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"engines"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"node"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&gt;=14.0.0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>如果本地运行的 Node 版本不匹配，yarn 将会报错，npm 则会打印警告信息。<code>engines</code> 字段不仅可以用于前端项目，也可用于第三方库。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>如果项目的 <code>package.json</code> 中没用 <code>engines</code> 字段，可查看 Dockerfile 中 node 镜像确定项目所需的 node 版本号。</p></div></div><p>📒 Vue SFC playground</p><p><a href="https://sfc.vuejs.org/" target="_blank" rel="noopener noreferrer">https://sfc.vuejs.org/</a></p><blockquote><p>研究下插槽的实现</p></blockquote><p>📒 写一个 Vue3 自定义指令</p><p>Vue 自定义指令的范式：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> lazyPlugin </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">app</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">directive</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'lazy'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// install 方法的第一个参数可以拿到 Vue 构造器</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 这块可以参考 Vue.use 源码</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> lazyPlugin</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在项目中使用如下：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> createApp </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'vue'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">App</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'./App.vue'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">lazyPlugin</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'vue3-lazy'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">createApp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token maybe-class-name">App</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">use</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lazyPlugin</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 添加一些配置参数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><a href="https://juejin.cn/post/7035916879092776968" target="_blank" rel="noopener noreferrer">手把手带你写一个 Vue3 的自定义指令</a></p><p>📒 <a href="https://juejin.cn/post/6922641008106668045" target="_blank" rel="noopener noreferrer">揭秘 Vue.js 九个性能优化技巧</a></p><p>📒 <a href="https://juejin.cn/post/6898865634982297613" target="_blank" rel="noopener noreferrer">2020最新React Hooks+TS项目最佳实践</a></p><p>📒 <a href="https://juejin.cn/post/6944863057000529933" target="_blank" rel="noopener noreferrer">「react进阶」一文吃透react-hooks原理</a></p><p>📒 <code>useCallback</code> 使用场景</p><p>在 React 中经常需要将父组件定义的方法传入子组件（即事件钩子，也可以看作子组件状态提升到父组件），例如：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name" style="color:#d73a49">Parent</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">handleSearch</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"搜索结果："</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onSearch</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">handleSearch</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">Input</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">memo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter punctuation" style="color:#393A34">{</span><span class="token parameter"> onSearch </span><span class="token parameter punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onSubmit</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript parameter" style="color:#00009f">e</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">      </span><span class="token tag script language-javascript keyword" style="color:#00009f">const</span><span class="token tag script language-javascript" style="color:#00009f"> submitData </span><span class="token tag script language-javascript operator" style="color:#393A34">=</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript known-class-name class-name" style="color:#00009f">Array</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript keyword module" style="color:#00009f">from</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">        e</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">target</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">childNodes</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">        </span><span class="token tag script language-javascript parameter" style="color:#00009f">item</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">name</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> item</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">name</span><span class="token tag script language-javascript punctuation" style="color:#393A34">,</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript literal-property property" style="color:#36acaa">value</span><span class="token tag script language-javascript operator" style="color:#393A34">:</span><span class="token tag script language-javascript" style="color:#00009f"> item</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">value</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">      </span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">;</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">      </span><span class="token tag script language-javascript function" style="color:#d73a49">onSearch</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">submitData</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">;</span><span class="token tag script language-javascript" style="color:#00009f"></span><br></span><span class="token-line" style="color:#393A34"><span class="token tag script language-javascript" style="color:#00009f">    </span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">search</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在上面的代码中，如果父组件重新渲染，则会导致 <code>handleSearch</code> 方法重新生成，进而导致 <code>onSearch</code> prop 改变，即使子组件用了 <code>React.memo</code>，子组件还是会重新渲染。在这种情况下，就可以使用 <code>useCallback</code> 缓存函数，避免函数重复生成，进而避免子组件重复渲染，提高性能：</p><div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name" style="color:#d73a49">Parent</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> handleSearch </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">useCallback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"搜索结果："</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onSearch</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">handleSearch</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_S0QG"><p>注意 <code>useCallback</code> 需要和 <code>React.memo</code> 一起使用。如果不用 <code>React.memo</code>，只要父组件重新渲染，即使 prop 没有改变，子组件还是会重新渲染</p><p><a href="https://juejin.cn/post/6844903985338400782" target="_blank" rel="noopener noreferrer">React Hooks 详解 【近 1W 字】+ 项目实战</a></p></div></div><p>📒 <a href="https://juejin.cn/post/7033210664844066853" target="_blank" rel="noopener noreferrer">老板：你来弄一个团队代码规范！？</a></p><p>📒 前端工程化系列文章</p><blockquote><p><a href="https://shanyue.tech/frontend-engineering/npm-install.html#%E4%BD%BF%E7%94%A8-npm-ci-%E6%9B%BF%E4%BB%A3-npm-i" target="_blank" rel="noopener noreferrer">https://shanyue.tech/frontend-engineering/npm-install.html#%E4%BD%BF%E7%94%A8-npm-ci-%E6%9B%BF%E4%BB%A3-npm-i</a></p></blockquote><p>📒 ES 新语法 <code>Array.prototype.groupBy</code></p><p>一个专门用来做数据分组的提案 <code>Array.prototype.groupBy</code> 已经到达 <code>Stage 3</code>：</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> array </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// groupBy groups items by arbitrary key.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// In this case, we're grouping by even/odd keys</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">groupBy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">num</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> index</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> array</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> num </span><span class="token operator" style="color:#393A34">%</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'even'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'odd'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// =&gt;  { odd: [1, 3, 5], even: [2, 4] }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p><a href="https://github.com/tc39/proposal-array-grouping" target="_blank" rel="noopener noreferrer">https://github.com/tc39/proposal-array-grouping</a></p></blockquote><p>📒 <a href="https://juejin.cn/post/7046204235226021901" target="_blank" rel="noopener noreferrer">基于 Next.js 的 SSR/SSG 方案了解一下？</a></p>]]></content>
        <author>
            <name>加菲猫</name>
            <uri>https://github.com/Jiacheng787</uri>
        </author>
        <category label="Next.js" term="Next.js"/>
        <category label="ESNext" term="ESNext"/>
        <category label="React" term="React"/>
        <category label="Vue" term="Vue"/>
        <category label="Node.js" term="Node.js"/>
        <category label="Performance" term="Performance"/>
        <category label="VS Code" term="VS Code"/>
        <category label="Git" term="Git"/>
        <category label="Yarn2" term="Yarn2"/>
        <category label="Code Review" term="Code Review"/>
    </entry>
</feed>