ZiuChen.github.io/note/Front-end Engineering.html

243 lines
141 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>前端工程化 | ZiuChen</title>
<meta name="description" content="Unlimited Progress.">
<link rel="preload stylesheet" href="/assets/style.60c127af.css" as="style">
<link rel="modulepreload" href="/assets/app.f4e2d6d1.js">
<link rel="modulepreload" href="/assets/note_Front-end Engineering.md.3f047f08.lean.js">
<link rel="icon" href="/logo.png">
<script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
</head>
<body>
<div id="app"><div class="Layout" data-v-3af881ed><!--[--><!--]--><!--[--><span tabindex="-1" data-v-00bddfc0></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-00bddfc0> Skip to content </a><!--]--><!----><header class="VPNav" data-v-3af881ed data-v-3796071a><div class="VPNavBar has-sidebar" data-v-3796071a data-v-fe00b0e5><div class="container" data-v-fe00b0e5><div class="title" data-v-fe00b0e5><div class="VPNavBarTitle has-sidebar" data-v-fe00b0e5 data-v-a7f91dcc><a class="title" href="/" data-v-a7f91dcc><!--[--><!--]--><!--[--><img class="VPImage logo" src="/logo.png" alt data-v-dca92699><!--]--><!--[-->ZiuChen<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-fe00b0e5><div class="curtain" data-v-fe00b0e5></div><div class="content-body" data-v-fe00b0e5><!--[--><!--]--><!----><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-fe00b0e5 data-v-a4f7fa5c><span id="main-nav-aria-label" class="visually-hidden" data-v-a4f7fa5c>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" data-v-a4f7fa5c data-v-1a106a35 data-v-8dd200cc><!--[-->首页<!--]--><!----></a><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-a4f7fa5c data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-e76b733c><span class="text" data-v-e76b733c><!----> 我的项目 <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-e76b733c><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><div class="items" data-v-faf23071><!--[--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/project/ClipboardManager/" data-v-c0d2d58e data-v-8dd200cc><!--[-->超级剪贴板<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/project/SmartWordBreak/" data-v-c0d2d58e data-v-8dd200cc><!--[-->超级分词<!--]--><!----></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-a4f7fa5c data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-e76b733c><span class="text" data-v-e76b733c><!----> 开源作品 <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-e76b733c><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><div class="items" data-v-faf23071><!--[--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/works/opensource.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->个人作品<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/works/contribution.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->社区贡献<!--]--><!----></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-a4f7fa5c data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-e76b733c><span class="text" data-v-e76b733c><!----> 学习笔记 <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-e76b733c><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><div class="items" data-v-faf23071><!--[--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/note/JavaScript.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->JavaScript基础<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/note/CSS.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->CSS基础<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link" href="/note/JavaScriptEnhanced.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->JavaScript进阶<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-faf23071 data-v-c0d2d58e><a class="VPLink link active" href="/note/Front-end%20Engineering.html" data-v-c0d2d58e data-v-8dd200cc><!--[-->前端工程化<!--]--><!----></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/article/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E4%BC%AA%E7%B1%BB%E4%B8%8E%E4%BC%AA%E5%85%83%E7%B4%A0.html" data-v-a4f7fa5c data-v-1a106a35 data-v-8dd200cc><!--[-->文章创作<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/self/" data-v-a4f7fa5c data-v-1a106a35 data-v-8dd200cc><!--[-->个人介绍<!--]--><!----></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-fe00b0e5 data-v-2d4753dd><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-label="toggle dark mode" aria-checked="false" data-v-2d4753dd data-v-867372a0 data-v-dc009bc3><span class="check" data-v-dc009bc3><span class="icon" data-v-dc009bc3><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-867372a0><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-867372a0><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-fe00b0e5 data-v-f0005c73 data-v-819d8281><!--[--><a class="VPSocialLink" href="https://ziuchen.github.io/" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink" href="https://juejin.cn/user/1887205216238477" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg width="36" height="28" viewBox="0 0 36 28" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M17.5875 6.77268L21.8232 3.40505L17.5875 0.00748237L17.5837 0L13.3555 3.39757L17.5837 6.76894L17.5875 6.77268ZM17.5863 17.3955H17.59L28.5161 8.77432L25.5526 6.39453L17.59 12.6808H17.5863L17.5825 12.6845L9.61993 6.40201L6.66016 8.78181L17.5825 17.3992L17.5863 17.3955ZM17.5828 23.2891L17.5865 23.2854L32.2133 11.7456L35.1768 14.1254L28.5238 19.3752L17.5865 28L0.284376 14.3574L0 14.1291L2.95977 11.7531L17.5828 23.2891Z" fill="#1E80FF"/></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-fe00b0e5 data-v-0467f0ad data-v-e76b733c><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-e76b733c><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-e76b733c><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-e76b733c><div class="VPMenu" data-v-e76b733c data-v-faf23071><!----><!--[--><!--[--><!----><div class="group" data-v-0467f0ad><div class="item appearance" data-v-0467f0ad><p class="label" data-v-0467f0ad>Appearance</p><div class="appearance-action" data-v-0467f0ad><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-label="toggle dark mode" aria-checked="false" data-v-0467f0ad data-v-867372a0 data-v-dc009bc3><span class="check" data-v-dc009bc3><span class="icon" data-v-dc009bc3><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-867372a0><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-867372a0><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-0467f0ad><div class="item social-links" data-v-0467f0ad><div class="VPSocialLinks social-links-list" data-v-0467f0ad data-v-819d8281><!--[--><a class="VPSocialLink" href="https://ziuchen.github.io/" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink" href="https://juejin.cn/user/1887205216238477" target="_blank" rel="noopener" data-v-819d8281 data-v-ba84061a><svg width="36" height="28" viewBox="0 0 36 28" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M17.5875 6.77268L21.8232 3.40505L17.5875 0.00748237L17.5837 0L13.3555 3.39757L17.5837 6.76894L17.5875 6.77268ZM17.5863 17.3955H17.59L28.5161 8.77432L25.5526 6.39453L17.59 12.6808H17.5863L17.5825 12.6845L9.61993 6.40201L6.66016 8.78181L17.5825 17.3992L17.5863 17.3955ZM17.5828 23.2891L17.5865 23.2854L32.2133 11.7456L35.1768 14.1254L28.5238 19.3752L17.5865 28L0.284376 14.3574L0 14.1291L2.95977 11.7531L17.5828 23.2891Z" fill="#1E80FF"/></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-fe00b0e5 data-v-f1813d69><span class="container" data-v-f1813d69><span class="top" data-v-f1813d69></span><span class="middle" data-v-f1813d69></span><span class="bottom" data-v-f1813d69></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav" data-v-3af881ed data-v-07d63927><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-07d63927><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-07d63927><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-07d63927>Menu</span></button><a class="top-link" href="#" data-v-07d63927>Return to top</a></div><aside class="VPSidebar" data-v-3af881ed data-v-eec6a639><div class="curtain" data-v-eec6a639></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-eec6a639><span class="visually-hidden" id="sidebar-aria-label" data-v-eec6a639> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>我的项目</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/project/ClipboardManager/" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>超级剪贴板</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/project/SmartWordBreak/" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>超级分词</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>开源作品</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/works/opensource.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>个人作品</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/works/contribution.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>社区贡献</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>文章创作</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E3%80%902023%E3%80%91%E9%9D%92%E8%AE%AD%E8%90%A5%20-%20%E5%89%8D%E7%AB%AF%E7%BB%83%E4%B9%A0%E9%A2%98%E6%B1%87%E6%80%BB%E8%A7%A3%E6%9E%90.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>【2023】青训营 - 前端练习题汇总解析</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1%E4%B8%8E%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>一文读懂事件冒泡与事件捕获</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E4%BC%AA%E7%B1%BB%E4%B8%8E%E4%BC%AA%E5%85%83%E7%B4%A0.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>一文读懂伪类与伪元素</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E5%87%BD%E6%95%B0%E4%B8%ADthis%E6%8C%87%E5%90%91%E9%97%AE%E9%A2%98.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>一文读懂函数中this指向问题</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E4%BB%8E0%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E5%B9%B4%E5%BA%A6%E6%8A%A5%E5%91%8A.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>从0实现一个年度报告</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%87%82%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%95%B0%E6%8D%AE%E5%B1%9E%E6%80%A7%E6%8F%8F%E8%BF%B0%E7%AC%A6%E3%80%81%E5%AD%98%E5%82%A8%E5%B1%9E%E6%80%A7%E6%8F%8F%E8%BF%B0%E7%AC%A6.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>彻底搞懂对象的数据属性描述符、存储属性描述符</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5Vue3%E6%BA%90%E7%A0%81%EF%BC%8C%E7%9C%8B%E7%9C%8BVue.use%E5%90%8E%E7%A9%B6%E7%AB%9F%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入Vue3源码看看Vue.use后究竟发生了什么</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Proxy%E4%B8%8EReflect.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入理解Proxy与Reflect</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98%E6%9C%BA%E5%88%B6.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入理解浏览器缓存机制</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/article/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E6%B5%8F%E8%A7%88%E5%99%A8%E8%BF%90%E8%A1%8C%E5%8E%9F%E7%90%86.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>深入理解浏览器运行原理</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><div class="group" data-v-eec6a639><section class="VPSidebarItem level-0 collapsible has-active" data-v-eec6a639 data-v-66b47b62><div class="item" role="button" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link" data-v-66b47b62 data-v-8dd200cc><!--[--><h2 class="text" data-v-66b47b62>学习笔记</h2><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-66b47b62><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-66b47b62><!--[--><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/JavaScript.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>JavaScript基础</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/CSS.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>CSS基础</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/JavaScriptEnhanced.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>JavaScript进阶</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><div class="VPSidebarItem level-1 is-link is-active has-active" data-v-66b47b62 data-v-66b47b62><div class="item" data-v-66b47b62><div class="indicator" data-v-66b47b62></div><a class="VPLink link link" href="/note/Front-end%20Engineering.html" data-v-66b47b62 data-v-8dd200cc><!--[--><p class="text" data-v-66b47b62>前端工程化</p><!--]--><!----></a><div class="caret" role="button" data-v-66b47b62><!----></div></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-3af881ed data-v-e31feb0e><div class="VPDoc has-sidebar has-aside" data-v-e31feb0e data-v-30dabfe4><div class="container" data-v-30dabfe4><div class="aside" data-v-30dabfe4><div class="aside-curtain" data-v-30dabfe4></div><div class="aside-container" data-v-30dabfe4><div class="aside-content" data-v-30dabfe4><div class="VPDocAside" data-v-30dabfe4 data-v-7110f5c9><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-7110f5c9 data-v-9c6f1a55><div class="content" data-v-9c6f1a55><div class="outline-marker" data-v-9c6f1a55></div><div class="outline-title" data-v-9c6f1a55>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-9c6f1a55><span class="visually-hidden" id="doc-outline-aria-label" data-v-9c6f1a55> Table of Contents for current page </span><ul class="root" data-v-9c6f1a55 data-v-02afc12d><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-7110f5c9></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-30dabfe4><div class="content-container" data-v-30dabfe4><!--[--><!--]--><main class="main" data-v-30dabfe4><div style="position:relative;" class="vp-doc _note_Front-end%20Engineering" data-v-30dabfe4><div><h1 id="前端工程化" tabindex="-1">前端工程化 <a class="header-anchor" href="#前端工程化" aria-hidden="true">#</a></h1><h2 id="node-js" tabindex="-1">Node.js <a class="header-anchor" href="#node-js" aria-hidden="true">#</a></h2><ul><li>什么是Node.JS Node的应用场景</li><li>JS代码执行</li><li>Node的输入和输出</li><li>Node的全局对象</li></ul><h3 id="什么是node-js" tabindex="-1">什么是Node.js <a class="header-anchor" href="#什么是node-js" aria-hidden="true">#</a></h3><p>Node.js是一个基于<strong>V8 JavaScript引擎</strong><strong>JavaScript运行时环境</strong></p><ul><li>V8可以嵌入到任何C++应用程序中无论是Chrome还是Node.js事实上都嵌入了V8引擎来执行JavaScript代码</li><li>在Chrome浏览器中还需要解析、渲染HTML、CSS等相关渲染引擎另外还需要支持浏览器操作的API、浏览器自己的事件循环</li><li>在Node.js中我们也需要进行一些额外操作文件系统读写、网络IO、加密、压缩解压文件等</li></ul><p>可以简单总结出Node.js和浏览器的区别</p><ul><li><p>Chrome浏览器</p><ul><li><p>Blink负责解析HTML文档遇到JavaScript标签时将内容交给V8引擎</p></li><li><blockquote><p>Blink 是 Google Chrome 浏览器的渲染引擎V8 是 Blink 内置的 JavaScript 引擎</p></blockquote><ul><li>预分析检查语法错误但不生成AST树</li><li>生成AST语法分析、词法分析后生成抽象语法树AST <ul><li>AST 为每一行代码定义键值对。初始类型标识符定义 AST 属于一个程序,然后所有代码行将定义在主体内部,主体是一个对象数组。</li></ul></li><li>生成字节码基线编译器Ignition将 AST 转换为字节码</li><li>生成机器代码:优化编译器 (Turbofan) 将字节码转换为优化的机器代码。另外,在逐行执行字节码的过程中,<strong>如果一段代码经常被执行V8会直接将这段代码转换并保存为机器码</strong>,下次执行不需要经过字节码,优化了执行速度</li></ul></li></ul></li><li><p>Node.js</p><ul><li>只处理JavaScript代码 内部V8引擎负责JS代码的执行</li><li>JavaScript代码 -&gt; V8 -&gt; Node.js Bindings -&gt; LibUV</li><li>LibUV是使用<strong>C语言编写的库</strong>,提供了<strong>事件循环、文件系统读写、网络IO、线程池</strong>等等内容</li></ul></li></ul><p>![The Node.js System](Front-end Engineering.assets/The Node.js System.jpeg)</p><h3 id="node-js的应用场景" tabindex="-1">Node.js的应用场景 <a class="header-anchor" href="#node-js的应用场景" aria-hidden="true">#</a></h3><ul><li>前端开发的库都是以node包形式管理的</li><li>npm yarn pnpm成为前端开发使用最多的工具</li><li>使用Node.js作为Web服务器开发、中间件、代理服务器</li><li>借助Node.js完成前后端渲染的同构应用</li><li>编写脚本工具 构建项目 打包代码等</li><li>Electron桌面应用程序</li></ul><h3 id="node-js的参数传递" tabindex="-1">Node.js的参数传递 <a class="header-anchor" href="#node-js的参数传递" aria-hidden="true">#</a></h3><h4 id="process-argv" tabindex="-1"><code>process.argv</code> <a class="header-anchor" href="#process-argv" aria-hidden="true">#</a></h4><p><code>process.argv</code>返回一个数组</p><ul><li>在代码中通过<code>process.argv[2]</code>读取来自命令行的额外参数</li><li><code>process.argv[0]</code> <code>process.argv[1]</code>分别为<code>node.exe</code>的绝对路径和<code>目标文件</code>的绝对路径</li></ul><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// sum.js</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> x </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> process</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">argv[</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">]</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> y </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> process</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">argv[</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">]</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(x </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> y)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><div class="language-sh line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 通过命令行运行node执行脚本 并传入参数</span></span>
<span class="line"><span style="color:#FFCB6B;">node</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">sum.js</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># 15</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="console" tabindex="-1">console <a class="header-anchor" href="#console" aria-hidden="true">#</a></h4><ul><li><code>console.log</code> 打印内容到stdout并加上换行符</li><li><code>console.clear</code> 清空当前stdout中的内容</li><li><code>console.trace</code> 打印字符串<code>Trace: </code>到stderr <ul><li>将堆栈跟踪打印到代码中的当前位置</li></ul></li></ul><h4 id="repl" tabindex="-1">REPL <a class="header-anchor" href="#repl" aria-hidden="true">#</a></h4><p>在浏览器的控制台选项卡中我们可以通过输入JS代码与之交互在Node.js中同样提供了类似的功能</p><ul><li>REPL是Read-Eval-Print Loop的简称翻译为读取-求值-输出循环</li><li>REPL是一个<strong>简单的、交互式的编程环境</strong></li><li>在命令行窗口中输入<code>node</code>即可进入</li></ul><h3 id="node中的全局对象" tabindex="-1">Node中的全局对象 <a class="header-anchor" href="#node中的全局对象" aria-hidden="true">#</a></h3><p>在浏览器中我们可以在JS代码中访问全局对象<code>window</code>,代表当前标签窗口</p><p>在Node.js中的全局对象名为<code>global</code>,在控制台输出<code>global</code>对象:</p><div class="language-sh line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> global</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;">ref </span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> Object </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">global</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">global:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Circular </span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">clearInterval:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Function: clearInterval</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">clearTimeout:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Function: clearTimeout</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">setInterval:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Function: setInterval</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">setTimeout:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Function: setTimeout</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Symbol(nodejs.util.promisify.custom)</span><span style="color:#89DDFF;">]</span><span style="color:#82AAFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Getter</span><span style="color:#89DDFF;">]</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">queueMicrotask:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Function: queueMicrotask</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">performance:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">Performance</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">nodeTiming:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">PerformanceNodeTiming</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">name:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">node</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">entryType:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">node</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">startTime:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">duration:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2245.9675999991596</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">nodeStart:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1.7120999991893768</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">v8Start:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7.749699998646975</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">bootstrapComplete:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">56.47019999846816</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">environment:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">28.44789999909699</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">loopStart:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">97.62589999847114</span><span style="color:#C3E88D;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">loopExit:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-1,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">idleTime:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2070.0206</span></span>
<span class="line"><span style="color:#A6ACCD;"> },</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">timeOrigin:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1675854922619.539</span></span>
<span class="line"><span style="color:#A6ACCD;"> },</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">clearImmediate:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Function: clearImmediate</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">setImmediate:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Function: setImmediate</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Symbol(nodejs.util.promisify.custom)</span><span style="color:#89DDFF;">]</span><span style="color:#82AAFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Getter</span><span style="color:#89DDFF;">]</span></span>
<span class="line"><span style="color:#A6ACCD;"> }</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br></div></div><h4 id="常见的全局对象" tabindex="-1">常见的全局对象 <a class="header-anchor" href="#常见的全局对象" aria-hidden="true">#</a></h4><ul><li><code>Buffer</code></li><li><code>clearImmediate</code></li><li><code>clearInterval</code></li><li><code>clearTimeout</code></li><li><code>console</code><ul><li>和控制台交互</li></ul></li><li><code>process</code><ul><li>提供了Node进程中相关的信息</li><li>Node的运行环境、系统环境变量、参数等</li></ul></li><li><code>queueMicrotask(callback)</code></li><li><code>setImmediate(callback, [, ...args])</code></li><li><code>setInterval(callback, delay[, ...args])</code></li><li><code>setTimeout(callback, delay[, ...args])</code></li><li><code>TextDecoder</code></li><li><code>TextEncoder</code></li><li><code>URL</code></li><li><code>URLSearchParams</code></li><li><code>WebAssembly</code></li></ul><h4 id="特殊的全局对象" tabindex="-1">特殊的全局对象 <a class="header-anchor" href="#特殊的全局对象" aria-hidden="true">#</a></h4><p><code>__dirname</code> <code>__filename</code> <code>exports</code> <code>module</code> <code>require()</code></p><ul><li>这些变量看起来是全局的,其实并不是(它们仅存在于模块范围内),只是每个模块中都有</li><li>它们在命令行交互中是不可使用的</li><li><code>__dirname</code> 当前模块的目录名</li><li><code>__filename</code> 当前模块的文件名</li><li><code>exports</code> <code>module</code> <code>require()</code>将在模块章节中讲解</li></ul><h4 id="global对象" tabindex="-1"><code>global</code>对象 <a class="header-anchor" href="#global对象" aria-hidden="true">#</a></h4><p><code>global</code>是一个全局对象</p><ul><li>在Node.js环境下之前的 <code>process</code> <code>console</code> <code>setTimeout</code>等都有被放入到<code>global</code></li><li>而在浏览器中这些全局API是被放到<code>window</code>对象上的</li></ul><p>这无异于增加了开发者的心智负担所以在最新的ECMA标准中出现了<code>globalThis</code>,指向全局对象</p><ul><li>在浏览器中的<code>globalThis</code>指向<code>window</code>对象</li><li>在Node.js中的<code>globalThis</code>指向<code>global</code>对象</li></ul><p>两个全局对象的区别:在浏览器中通过<code>var</code>定义的变量会被放到<code>window</code>对象上而Node.js不会</p><h2 id="模块化开发" tabindex="-1">模块化开发 <a class="header-anchor" href="#模块化开发" aria-hidden="true">#</a></h2><ul><li>认识模块化开发</li><li>CommonJS和Node</li><li>require函数解析</li><li>AMD和CMD已经被时代淘汰 了解即可)</li><li>ESModule用法详解</li><li>ESModule运行原理</li></ul><h3 id="模块化的初衷" tabindex="-1">模块化的初衷 <a class="header-anchor" href="#模块化的初衷" aria-hidden="true">#</a></h3><ul><li>将大的程序拆分成一个个小的易于维护的代码</li><li>每个模块负责程序中的一部分逻辑,拥有<strong>自己的作用域</strong><strong>定义变量名时不会发生冲突</strong></li><li>模块可以暴露<strong>变量、函数、对象</strong>等导出</li><li>模块可以导入其他模块的<strong>变量、函数、对象</strong></li></ul><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// moduleA.js</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> moduleA </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> (</span><span style="color:#C792EA;">function</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#C792EA;">const</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">name</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">=</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">Ziu</span><span style="color:#89DDFF;">&quot;</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#C792EA;">const</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">age</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">=</span><span style="color:#F07178;"> </span><span style="color:#F78C6C;">18</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#C792EA;">const</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">run</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">=</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">()</span><span style="color:#F07178;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;">name</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">+</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">age</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">+</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">is running.</span><span style="color:#89DDFF;">&#39;</span><span style="color:#F07178;">)</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">name</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">age</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">run</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">)()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">// moduleB.js</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(moduleA</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">name) </span><span style="color:#676E95;font-style:italic;">// 在其他模块中调用</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><h3 id="commonjs" tabindex="-1">CommonJS <a class="header-anchor" href="#commonjs" aria-hidden="true">#</a></h3><p>CommonJS是一种<strong>规范</strong>当初命名为ServerJS旨在浏览器以外的地方使用后为体现其广泛性改名为CommonJS简称CJS</p><p><strong>规范 是用来指导 实现的</strong></p><ul><li><code>Node</code> 是CommonJS在服务端的代表<strong>实现</strong></li><li><code>Browserify</code> 是CommonJS在浏览器中的一种<strong>实现</strong> (正在被淘汰)</li><li><code>WebPack</code> 打包工具具备支持CommonJS的支持和转换</li></ul><p>所以Node.js对CommonJS进行了支持和实现让JavaScript在Node上运行时可以实现模块化开发</p><ul><li>每个<code>.js</code>文件都是一个单独的模块</li><li>每个模块中都包含变量<code>exports</code> <code>module.exports</code> <code>require</code></li></ul><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-XAAzA" id="tab-vbwwoiz" checked="checked"><label for="tab-vbwwoiz">env.js</label><input type="radio" name="group-XAAzA" id="tab-o8FxUD-"><label for="tab-o8FxUD-">utils.js</label><input type="radio" name="group-XAAzA" id="tab-UOvbrPc"><label for="tab-UOvbrPc">index.js</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// env.js</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">name </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Ziu</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">18</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// utils.js</span></span>
<span class="line"><span style="color:#89DDFF;">module.exports</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">sum</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">function</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">x</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">y</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">x</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">+</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">y</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// index.js</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> utils </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">utils.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">utils</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">sum</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">) </span><span style="color:#676E95;font-style:italic;">// 3</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#A6ACCD;"> sum </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">utils.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#82AAFF;">sum</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">) </span><span style="color:#676E95;font-style:italic;">// 3</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#A6ACCD;"> name</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">env.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(name</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> age) </span><span style="color:#676E95;font-style:italic;">// Ziu 18</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div></div></div><h4 id="exports的本质" tabindex="-1"><code>exports</code>的本质 <a class="header-anchor" href="#exports的本质" aria-hidden="true">#</a></h4><p><code>exports</code><code>require</code>在Node中的本质</p><ul><li><code>exports</code>是一个对象,我们可以在这个对象中添加很多属性,添加的属性则会被导出 <ul><li>在没有向该对象添加任何属性之前,它是一个空对象</li></ul></li><li>当通过<code>require</code>导入时:<code>const env = require(&#39;env.js&#39;)</code><ul><li><code>env</code>这个变量等于<code>env.js</code>中的<code>exports</code>对象</li><li>本质上是<code>env</code><code>exports</code>对象的引用赋值</li><li><code>{ id: &#39;...&#39;, exports: { ... }, loaded: true, ... }</code></li></ul></li><li>后续即使再次执行<code>require</code>导入模块,模块中的代码也不会重新执行(<code>module.loaded</code>属性) <ul><li>当从模块中取值时,会从已经加载的<code>exports</code>对象缓存上取值</li></ul></li></ul><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-PJ4fi" id="tab-HLt88Yi" checked="checked"><label for="tab-HLt88Yi">utils.js</label><input type="radio" name="group-PJ4fi" id="tab-S24bxlN"><label for="tab-S24bxlN">index.js</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// utils.js</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">a </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">// 1s后修改a值</span></span>
<span class="line"><span style="color:#82AAFF;">setTimeout</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">=</span><span style="color:#F07178;"> </span><span style="color:#F78C6C;">1</span></span>
<span class="line"><span style="color:#89DDFF;">},</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">// 2s后检查a值</span></span>
<span class="line"><span style="color:#82AAFF;">setTimeout</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;">) </span><span style="color:#676E95;font-style:italic;">// 2</span></span>
<span class="line"><span style="color:#89DDFF;">},</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2000</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// index.js</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> utils </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./utils</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(utils</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">a) </span><span style="color:#676E95;font-style:italic;">// 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#82AAFF;">setTimeout</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;">utils</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;">) </span><span style="color:#676E95;font-style:italic;">// 1</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">utils</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">=</span><span style="color:#F07178;"> </span><span style="color:#F78C6C;">2</span><span style="color:#F07178;"> </span><span style="color:#676E95;font-style:italic;">// 反过来修改a值</span></span>
<span class="line"><span style="color:#89DDFF;">},</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1500</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div></div></div><p>在上述代码中,<code>utils</code>对象中的属性<code>a</code>在一秒后被赋值为<code>1</code>因此在index.js中输出<code>utils.a</code>得到了两次不同的结果</p><p>反过来在index.js中修改导入的<code>utils.a</code>的值后,修改结果也会反映在<code>exports.a</code>上,输出的值为<code>2</code></p><p>实际开发中不要修改导入模块中的变量,改变原模块中变量的值并不规范</p><h4 id="module-exports" tabindex="-1"><code>module.exports</code> <a class="header-anchor" href="#module-exports" aria-hidden="true">#</a></h4><p>在Node.js中真正常用的导出方式是<code>module.exports</code></p><ul><li><code>module.exports</code>本质上就是<code>exports</code>对象(同一个内存地址)</li><li>可以直接给<code>exports</code>对象赋值,将需要导出的内容统一导出</li><li><code>module.exports</code>重新赋值,即改变了<code>exports</code>对象的指向,<strong>后续的修改不再影响原模块中的变量</strong></li></ul><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> name </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Ziu</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> run </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(name </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">is running.</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">module.exports</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> name</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;"> run</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h4 id="二者的区别" tabindex="-1">二者的区别 <a class="header-anchor" href="#二者的区别" aria-hidden="true">#</a></h4><p>既然如此,为什么还要存在<code>exports</code>这个概念呢?</p><ul><li>在CommonJS中是没有<code>module.exports</code>的概念的</li><li>为了实现模块的导出Node.js使用的是<code>Module</code>类,每一个模块都是<code>Module</code>的实例,也就是<code>module</code></li><li>所以在Node.js中真正用于导出的并不是<code>exports</code>,而是<code>module.exports</code></li><li><code>module</code>对象中的<code>exports</code>属性是<code>exports</code>对象的一个引用 <ul><li><code>module.exports === exports === utils</code></li></ul></li></ul><p>如果<code>module.exports</code>不再引用<code>exports</code>对象了,修改<code>exports</code>对象也就没有意义了</p><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-4gW9S" id="tab-ei4J1t3" checked="checked"><label for="tab-ei4J1t3">utils.js</label><input type="radio" name="group-4gW9S" id="tab-Kn4P6Ew"><label for="tab-Kn4P6Ew">index.js</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// utils.js</span></span>
<span class="line"><span style="color:#89DDFF;">module.exports</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F07178;">name</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Ziu</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">18</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// index.js</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> utils </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">utils.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(utils</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">name) </span><span style="color:#676E95;font-style:italic;">// Ziu</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(utils</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">age) </span><span style="color:#676E95;font-style:italic;">// undefined</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div></div></div><p>当使用<code>module.exports = { ... }</code>后,模块中原有的<code>exports</code>不再被导入识别,导入的内容将变为<code>module.exports</code>指定的对象内容</p><h4 id="require的本质" tabindex="-1"><code>require</code>的本质 <a class="header-anchor" href="#require的本质" aria-hidden="true">#</a></h4><p><code>require</code>是一个函数,可以帮助我们导入一个文件(模块)中导出的对象</p><ul><li>为什么可以省略掉<code>.js</code>后缀,直接使用<code>require(&#39;./utils&#39;)</code></li><li>为什么可以省略掉<code>index.js</code>,直接使用<code>require(&#39;./tools&#39;)</code>导入<code>tools/index.js</code></li></ul><p>这涉及到<code>require</code>在匹配路径后的查找规则:</p><p>分为三种情况:<strong>内置模块、自定义路径、包名</strong></p><ul><li>导入Node.js内置的模块<code>const path = require(&#39;path&#39;)</code><ul><li>直接返回该内置模块 并停止后续的查找</li></ul></li><li>根据路径导入自定义的模块,如<code>const utils = require(&#39;./{filename}&#39;)</code><ul><li>按照路径寻找该模块<code>./</code> <code>../</code> <code>/</code></li><li>如果指定了后缀名,则按照后缀名查找</li><li>如果未指定后缀名,则: <ol><li>直接查找该文件</li><li>查找<code>{filename}.js</code>文件</li><li>查找<code>{filename}.json</code>文件</li><li>查找<code>{filename}.node</code>文件</li></ol></li><li>如果按照上述方式没找到文件,则<strong><code>{filename}</code>作为路径继续查找</strong></li><li>查找目录下的<code>index</code>文件 <code>{filename}/index</code><ol><li>查找<code>{filename}/index.js</code>文件</li><li>··· ···</li></ol></li><li>没找到:报错<code>Cannot find module &#39;xxx&#39;</code></li></ul></li><li>包名,如<code>const lodash = require(&#39;lodash&#39;)</code><ul><li>到项目根目录的<code>node_modules</code>中查找</li><li><code>node_modules/{package_name}/index.js</code></li><li>当前项目目录的<code>node_modules</code>找不到则继续向上查找,直到查找到根目录的<code>node_modules</code></li></ul></li></ul><h4 id="模块的加载过程" tabindex="-1">模块的加载过程 <a class="header-anchor" href="#模块的加载过程" aria-hidden="true">#</a></h4><ul><li>模块在被第一次引入时模块中的JS代码会被运行一次 <ul><li>代码执行顺序与<code>require</code>的位置相关</li></ul></li><li>模块如果被多次引入,会被缓存,最终只加载一次 <ul><li>这是因为每个模块对象<code>module</code>上都有一个属性<code>loaded</code></li><li><code>loaded === false</code>表示该模块尚未被加载</li><li>第二次被<code>require</code>引入时会检查该属性是否为<code>true</code></li></ul></li><li>如果有循环引用,加载顺序如何? <ul><li>数据结构图结构graph遍历时有深度优先搜索DFS、广度优先搜索BFS两种算法</li><li>Node采用的是深度优先算法</li></ul></li></ul><h4 id="commonjs的缺点" tabindex="-1">CommonJS的缺点 <a class="header-anchor" href="#commonjs的缺点" aria-hidden="true">#</a></h4><ul><li>加载模块是同步加载的 <ul><li>只有等到对应的模块加载完毕,当前模块中的内容才能被执行</li><li>当然在服务器中加载JS文件都是本地文件加载速度非常快不会受影响</li></ul></li><li>但是在浏览器中使用CommonJS <ul><li>需要先从服务器下载JS文件后加载运行</li><li>阻塞JS执行 阻塞页面加载</li></ul></li><li>在WebPack中使用CommonJS <ul><li>CommonJS会被WebPack解析</li><li>将CommonJS代码转化为bundle 浏览器可以直接运行</li></ul></li></ul><h3 id="esmodule" tabindex="-1">ESModule <a class="header-anchor" href="#esmodule" aria-hidden="true">#</a></h3><ul><li>ES6 模块采用<strong>编译时加载</strong>,使得<strong>编译时就能确定模块的依赖关系</strong>,有助于<strong>静态优化</strong></li><li>CommonJS模块在运行时加载且必须借助对象加载模块内容</li></ul><h4 id="export和import用法概览" tabindex="-1"><code>export</code><code>import</code>用法概览 <a class="header-anchor" href="#export和import用法概览" aria-hidden="true">#</a></h4><p>ESModule借助<code>export</code><code>import</code>导入导出内容,需要注意的是导入导出的并不是对象</p><p><code>export</code>定义的是当前模块导出的<strong>接口</strong><code>import</code>可以导入来自其他不同模块的<strong>接口</strong></p><ul><li><code>export default</code>可以设置默认导出对象</li><li><code>export { ... }</code>可以统一导出多个内容</li><li><code>export</code><code>import</code>都可以使用<code>as</code>关键字重命名导出/导入的接口</li><li><code>import * from &#39;xxx&#39;</code> <code>export * from &#39;xxx&#39;</code>批量导入/导出</li></ul><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-NZabR" id="tab-4NY8W7B" checked="checked"><label for="tab-4NY8W7B">utils.js</label><input type="radio" name="group-NZabR" id="tab-rCd8TAV"><label for="tab-rCd8TAV">index.js</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// utils.js</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">sum</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">a</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">b</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">+</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">b</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">sub</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">a</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">b</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">b</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">log</span><span style="color:#89DDFF;">(...</span><span style="color:#A6ACCD;font-style:italic;">args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">...</span><span style="color:#A6ACCD;">args</span><span style="color:#F07178;">)</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">name</span><span style="color:#F07178;">: &#39;</span><span style="color:#A6ACCD;">Ziu</span><span style="color:#F07178;">&#39;</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">age</span><span style="color:#F07178;">: 18</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> ENV_VARIABLE </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Hello, World!</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// index.js</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">sum</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">sub</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">name</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">age</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">ENV_VARIABLE</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./utils</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> log </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./utils.js</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#82AAFF;">sum</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">) </span><span style="color:#676E95;font-style:italic;">// 3</span></span>
<span class="line"><span style="color:#82AAFF;">sub</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">) </span><span style="color:#676E95;font-style:italic;">// -1</span></span>
<span class="line"><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(name</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> age</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> ENV_VARIABLE) </span><span style="color:#676E95;font-style:italic;">// &#39;Ziu&#39; 18 &#39;Hello, World!&#39;</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div></div></div><p>需要注意的是在浏览器中要使用ESModule需要为<code>&lt;script&gt;</code>标签添加<code>module</code>标记:</p><p><code>&lt;script src=&quot;index.js&quot; type=&quot;module&quot;&gt;&lt;/script&gt;</code></p><ul><li>当浏览器解析到<code>type=&quot;module&quot;</code>的JS代码后<strong>分析模块中导入的ESModule模块</strong></li><li>每导入一个ESModule模块<strong>浏览器都会发起一个HTTP请求去加载它</strong></li><li>在本地运行时加载不同协议头的文件会遇到跨域问题需要开启本地Web服务器</li></ul><p>另外,<strong><code>export</code><code>import</code>必须位于模块的顶层</strong>,如果位于作用域内会报错,因为这就<strong>无法对代码进行静态分析优化了</strong></p><h4 id="export详解" tabindex="-1"><code>export</code>详解 <a class="header-anchor" href="#export详解" aria-hidden="true">#</a></h4><p><code>export</code>有两种导出方式:</p><ul><li>命名导出 <code>export const name = &#39;Ziu&#39;</code> <code>export { v1, v2 } export * from &#39;xxx&#39;</code><ul><li>导出时需要指定名字</li><li>导入时也需要知道对应的名字</li></ul></li><li>默认导出 <code>export default AGE = 18</code><ul><li>在从其他位置导入时需要为此默认导出指定新的名字</li><li>给用户方便:不必阅读文档就可以加载模块</li></ul></li></ul><h4 id="值的动态绑定" tabindex="-1">值的动态绑定 <a class="header-anchor" href="#值的动态绑定" aria-hidden="true">#</a></h4><ul><li>ESModule模块通过<code>export</code>语句输出的接口,与其对应的值是<strong>动态绑定关系</strong>,即通<strong>过该接口,可以取到模块内部实时的值</strong></li><li>CommonJS模块输出的是值的缓存不存在动态更新</li></ul><p>我们援引之前介绍CJS时的案例<strong>将后缀名改为<code>mjs</code>即可在Node中运行ESModule模块代码</strong></p><p>初始获得的<code>a</code>值为0经过1s后<code>utils.mjs</code>中修改了a的值这时导入<code>utils.mjs</code>模块的其他模块可以获取到<code>a</code>最新的值</p><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-BU1Qd" id="tab-NEKy_NE" checked="checked"><label for="tab-NEKy_NE">utils.mjs</label><input type="radio" name="group-BU1Qd" id="tab-Ed7Mi3g"><label for="tab-Ed7Mi3g">index.mjs</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// utils.mjs</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">let</span><span style="color:#A6ACCD;"> a </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">// 1s后修改a值</span></span>
<span class="line"><span style="color:#82AAFF;">setTimeout</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">=</span><span style="color:#F07178;"> </span><span style="color:#F78C6C;">1</span></span>
<span class="line"><span style="color:#89DDFF;">},</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// index.mjs</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./utils.mjs</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(a) </span><span style="color:#676E95;font-style:italic;">// 0</span></span>
<span class="line"></span>
<span class="line"><span style="color:#82AAFF;">setTimeout</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;">a</span><span style="color:#F07178;">) </span><span style="color:#676E95;font-style:italic;">// 1</span></span>
<span class="line"><span style="color:#89DDFF;">},</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1500</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div></div></div><ul><li>需要注意的是,导入的其他模块的变量是不允许被修改的,因为<code>index.mjs</code>导入的本质是一个接口</li><li>如果从其他模块导入的是一个对象,也不推荐修改导入内容的任何值,最好将其当做完全只读</li></ul><p>拓展阅读CommonJS与ESModule加载模块的异同</p><h4 id="import详解" tabindex="-1"><code>import</code>详解 <a class="header-anchor" href="#import详解" aria-hidden="true">#</a></h4><p>检查下述代码:</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#82AAFF;">foo</span><span style="color:#A6ACCD;">()</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">foo</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">foo</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><ul><li><code>import</code>命令具有提升效果,会提升到整个模块的顶部</li><li><code>import</code>的执行早于函数的调用,<code>import</code>命令是在编译阶段执行的,在代码运行之前</li><li>由于<code>import</code>是静态执行,所以不能使用表达式和变量(只有运行时才有值)</li></ul><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">lodash</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">lodash</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><ul><li>如果仅仅导入了一个模块,那么该模块的代码会被执行,但是没有任何变量被导入</li><li>如果同一模块被导入多次,那么导入操作只会被执行一次</li></ul><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">utils</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#82AAFF;">add</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">utils</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><ul><li>可以通过<code>*</code>一次性导入模块中所有导出的变量、函数、类</li><li>也可以实现二者的复合操作:导入全部模块的同时导出全部模块</li></ul><h4 id="import-函数" tabindex="-1"><code>import()</code>函数 <a class="header-anchor" href="#import-函数" aria-hidden="true">#</a></h4><p>通过<code>import</code>命令导入的模块是静态的,会被提升到模块顶部,并不支持条件导入</p><p>ES2020引入了<code>import()</code>函数,可以通过<code>import()</code>函数实现条件导入动态加载ESModule模块</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> main </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> document</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">querySelector</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">main</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">import</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">./section-modules/</span><span style="color:#89DDFF;">${</span><span style="color:#A6ACCD;">someVariable</span><span style="color:#89DDFF;">}</span><span style="color:#C3E88D;">.js</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">then</span><span style="color:#A6ACCD;">(</span><span style="color:#A6ACCD;font-style:italic;">module</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">module.</span><span style="color:#82AAFF;">loadPageInto</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;">main</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">catch</span><span style="color:#A6ACCD;">(</span><span style="color:#A6ACCD;font-style:italic;">err</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">main</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">textContent</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">=</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">err</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">message</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><ul><li>返回值是一个Promise对象可以通过<code>await</code>同步地操作它</li><li><code>import()</code>函数可以在模块外的JS脚本中使用用于<strong>在运行时加载外部模块</strong>,类似于<code>require()</code></li><li>区别于<code>require()</code><code>import()</code>是异步加载模块</li></ul><p>通过<code>.then</code>函数处理导入的模块时,行为和<code>import</code>是相同的:</p><ul><li>如果有默认导出对象,则<code>.then</code>入参为默认导出对象</li><li>可以通过解构直接取到模块中导出的变量或函数:<code>.then(({ add, sub }) =&gt; { ... })</code></li></ul><p><strong>应用场景</strong></p><p>按需加载按钮点击后才加载相关的JS文件</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">btn</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">click</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">import</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./dialogBox.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#F07178;">)</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">then</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;font-style:italic;">dialogBox</span><span style="color:#F07178;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">dialogBox</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">open</span><span style="color:#F07178;">()</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#F07178;">)</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">catch</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;font-style:italic;">err</span><span style="color:#F07178;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#A6ACCD;">err</span><span style="color:#F07178;">))</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>条件加载根据主题色加载不同JS文件</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;">(darkMode) </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">import</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">dark.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">then</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">()</span><span style="color:#F07178;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">...</span><span style="color:#F07178;">)</span></span>
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">else</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;">import</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">light.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">then</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">()</span><span style="color:#F07178;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">...</span><span style="color:#F07178;">)</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>传入动态值</p><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">let</span><span style="color:#A6ACCD;"> moduleName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">=&gt;</span><span style="color:#A6ACCD;"> [</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Home</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">History</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">User</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">][</span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">]</span></span>
<span class="line"><span style="color:#89DDFF;">import</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">./</span><span style="color:#89DDFF;">${</span><span style="color:#82AAFF;">moduleName</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">}</span><span style="color:#C3E88D;">.js</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="import-meta" tabindex="-1"><code>i<wbr>mport.meta</code> <a class="header-anchor" href="#import-meta" aria-hidden="true">#</a></h4><p>ES2020引入了<code>i<wbr>mport.meta</code>,它仅能在模块内部使用,包含一些模块自身的信息,即模块元信息</p><ul><li><code>i<wbr>mport.meta.url</code> 返回当前模块的URL路径 <ul><li>浏览器加载ESModule都是通过HTTP发起请求 <ul><li>例如当前模块为<code>fetchData.js</code>,要在模块内引入一个名为<code>data.json</code>的数据:</li><li><code>import( new URL(&#39;data.json&#39;, i<wbr>mport.meta.url) )</code></li></ul></li><li>Node.js环境下该值都是<code>file://</code>协议的链接</li></ul></li><li><code>i<wbr>mport.meta.scriptElement</code><ul><li>浏览器特有的属性</li><li>返回加载模块的<code>&lt;script&gt;</code>标签,相当于<code>document.currentScript</code></li></ul></li></ul><p>规范中并未规定<code>i<wbr>mport.meta</code>中包含哪些属性,一般包括上面两个属性</p><h3 id="深入理解模块加载" tabindex="-1">深入理解模块加载 <a class="header-anchor" href="#深入理解模块加载" aria-hidden="true">#</a></h3><h4 id="esmodule的解析过程" tabindex="-1">ESModule的解析过程 <a class="header-anchor" href="#esmodule的解析过程" aria-hidden="true">#</a></h4><p>ESModule的解析过程可以分为三个阶段</p><ul><li>构建 <code>Construction</code><ul><li>根据地址查找JS文件并发起HTTP请求下载将其解析为模块记录 <code>Module Record</code></li></ul></li><li>实例化 <code>Instatiation</code><ul><li>对模块记录进行实例化,并为其分配内存空间</li><li>解析ESModule模块的<strong>导入和导出</strong>语句,将模块指向对应的内存地址</li><li>例如<code>export const name = &#39;Ziu&#39;</code>,会将变量<code>name</code>添加到模块环境记录中 <code>Module Enviroment Record</code></li></ul></li><li>运行 <code>Evaluation</code><ul><li>运行代码,计算值,并且将值填充到内存地址中</li><li>将导入导出的<strong></strong>赋给对应的变量<code>name = &#39;Ziu&#39;</code></li></ul></li></ul><p><img src="https://hacks.mozilla.org/files/2018/03/07_3_phases.png" alt="ESModule解析过程"></p><p>文章推荐:<a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/" target="_blank" rel="noreferrer">ES modules: A cartoon deep-dive</a></p><h4 id="mjs和cjs的区别" tabindex="-1">MJS和CJS的区别 <a class="header-anchor" href="#mjs和cjs的区别" aria-hidden="true">#</a></h4><ul><li><strong>CommonJS模块输出的是值的拷贝而ESModule模块输出的是值的引用</strong><ul><li>CJS导出的变量其值如果在模块内发生变化外部导入是不会同步更新的除非导出的是一个取值函数</li><li>MJS导出变量外部模块每次访问时都会得到该变量最新的值即使变量在模块内被修改了</li></ul></li><li><strong>CommonJS模块是运行时加载而ESModule是编译时输出接口</strong><ul><li>CJS是<strong>通过对象实现</strong>的导入导出,它<strong>在运行时才被确定依赖关系</strong>和其值</li><li>MJS则是<strong>通过静态定义</strong>,在代码运行之前的<strong>静态解析阶段即可确定模块的导入导出内容</strong></li></ul></li><li><strong>CommonJS模块的<code>require()</code>是同步加载模块而ESModule模块的<code>import</code>命令是异步加载模块</strong><ul><li><code>import</code>命令拥有一个独立的模块依赖的解析阶段</li></ul></li></ul><h4 id="cjs中的循环加载" tabindex="-1">CJS中的循环加载 <a class="header-anchor" href="#cjs中的循环加载" aria-hidden="true">#</a></h4><p>设想有以下两文件 <code>a.js</code><code>b.js</code></p><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-X6fqn" id="tab-BvUxYTB" checked="checked"><label for="tab-BvUxYTB">a.js</label><input type="radio" name="group-X6fqn" id="tab-dquqOAo"><label for="tab-dquqOAo">b.js</label><input type="radio" name="group-X6fqn" id="tab-HYeE9Xd"><label for="tab-HYeE9Xd">main.js</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// a.js</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">done </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FF9CAC;">false</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> b </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./b.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">在 a.js 之中b.done = %j</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> b</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">done)</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">done </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FF9CAC;">true</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a.js 执行完毕</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// b.js</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">done </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FF9CAC;">false</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> a </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./a.js</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">在 b.js 之中a.done = %j</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> a</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">done)</span></span>
<span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">done </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FF9CAC;">true</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">b.js 执行完毕</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// main.js</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> a </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./a</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#A6ACCD;"> b </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./b</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">在 main.js 之中, a.done=%j, b.done=%j</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> a</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">done</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> b</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">done)</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div></div></div><p>执行脚本<code>main.js</code>,先执行<code>a.js</code></p><ul><li>第一行 导出<code>done</code>值为<code>false</code></li><li>第二行 <code>a.js</code>的代码暂停执行 进入<code>b.js</code>并等待其执行完毕</li></ul><p><code>b.js</code>中:</p><ul><li>第一行 导出<code>done</code>值为<code>false</code></li><li>第二行 执行<code>a.js</code><code>a.js</code>模块中取<code>exports</code>对象</li><li><strong>取到其缓存值为<code>false</code><code>a.js</code>执行已经执行的部分)</strong></li><li>随后<code>b.js</code>继续向下执行 执行完毕后 将执行权交还给<code>a.js</code></li></ul><p>回到<code>a.js</code>中:</p><ul><li>继续向后执行 直到代码执行完毕</li></ul><p>最终输出:</p><div class="language-sh line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;"></span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">b.js</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">之中a.done</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">false</span></span>
<span class="line"><span style="color:#FFCB6B;">b.js</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">执行完毕</span></span>
<span class="line"><span style="color:#FFCB6B;"></span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">a.js</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">之中b.done</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">true</span></span>
<span class="line"><span style="color:#FFCB6B;">a.js</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">执行完毕</span></span>
<span class="line"><span style="color:#FFCB6B;"></span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">main.js</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">之中,</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">a.done=</span><span style="color:#89DDFF;">true</span><span style="color:#C3E88D;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">b.done=</span><span style="color:#89DDFF;">true</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>总结:</p><ul><li>CJS的模块导出是输出值的拷贝而不是引用值的变化不是动态的而是会被缓存的</li><li>循环加载时CJS模块导出的值是当前已经执行部分代码产生的结果的值而不是模块代码完全执行完后的最终值</li></ul><h4 id="mjs中的循环加载" tabindex="-1">MJS中的循环加载 <a class="header-anchor" href="#mjs中的循环加载" aria-hidden="true">#</a></h4><p>ESModule的导入和导出与CommonJS有本质不同</p><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-ijy5d" id="tab-FMSxdfJ" checked="checked"><label for="tab-FMSxdfJ">a.mjs</label><input type="radio" name="group-ijy5d" id="tab-8CO0rm_"><label for="tab-8CO0rm_">b.mjs</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// a.mjs</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">bar</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./b.mjs</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a.mjs</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(bar)</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">let</span><span style="color:#A6ACCD;"> foo </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">foo</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// b.mjs</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">foo</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./a.mjs</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">b.mjs</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(foo)</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">let</span><span style="color:#A6ACCD;"> bar </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">bar</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div></div></div><p>执行<code>a.mjs</code>后发现报错了:<code>ReferenceError: Cannot access &#39;foo&#39; before initialization</code>,变量<code>foo</code>未定义</p><ul><li>MJS模块在代码执行前会进行静态分析</li><li>分析<code>a.mjs</code>的依赖关系时,发现其依赖了<code>b.mjs</code></li><li>于是加载<code>b.mjs</code>并解析它的依赖关系</li><li>解析<code>b.mjs</code>的过程中,发现它又依赖了<code>a.mjs</code></li><li>这时引擎不会再去加载<code>a.mjs</code> 而是认为<code>a.mjs</code>这个模块的<code>Module Record</code>已经存在了</li><li>继续向下执行,执行到<code>console.log(foo)</code>时发现<code>foo</code>未定义 抛出错误</li></ul><p>要实现预期效果,可以将<code>foo</code><code>bar</code>改写为取值函数,这时执行就不会报错了:</p><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-DY0oJ" id="tab-Sx-FeMG" checked="checked"><label for="tab-Sx-FeMG">a.mjs</label><input type="radio" name="group-DY0oJ" id="tab-IzsdUCm"><label for="tab-IzsdUCm">b.mjs</label></div><div class="blocks"><div class="language-js active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// a.mjs</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">bar</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./b.mjs</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a.mjs</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#82AAFF;">bar</span><span style="color:#A6ACCD;">())</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">foo</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">foo</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><div class="language-js line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// b.mjs</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#A6ACCD;">foo</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">./a.mjs</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">b.mjs</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(</span><span style="color:#82AAFF;">foo</span><span style="color:#A6ACCD;">())</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">bar</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#F07178;"> </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">bar</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div></div></div><p>这是因为函数<code>function</code>具有提升作用,在<code>a.mjs</code>中执行<code>import { bar } from &#39;./b.mjs&#39;</code>之前,<code>foo</code>就有定义了。</p><p>因此在进入<code>b.mjs</code>执行<code>console.log(foo())</code>时可以取到<code>foo</code>,代码可以顺利执行</p><p>另:如果将<code>foo</code>定义为函数表达式<code>export const foo = () =&gt; &#39;foo&#39;</code>,由于没有变量提升,代码仍然会报错</p><h4 id="内部变量差异" tabindex="-1">内部变量差异 <a class="header-anchor" href="#内部变量差异" aria-hidden="true">#</a></h4><p>ESModule和CommonJS另一个重要区别就是</p><p>ESModule模块是在浏览器与服务端通用的之前在解读CommonJS时介绍了它拥有的一些内部变量模块变量</p><ul><li><code>arguments</code></li><li><code>require</code></li><li><code>module</code></li><li><code>exports</code></li><li><code>__filename</code></li><li><code>_dirname</code></li></ul><p>这些变量在ESModule模块中都是不存在的且顶层的<code>this</code>不再指向当前模块,而是<code>undefined</code></p><h3 id="拓展内容" tabindex="-1">拓展内容 <a class="header-anchor" href="#拓展内容" aria-hidden="true">#</a></h3><h4 id="在node-js中使用esmodule" tabindex="-1">在Node.js中使用ESModule <a class="header-anchor" href="#在node-js中使用esmodule" aria-hidden="true">#</a></h4><p>在Node.js中普通的<code>.js</code>文件会被默认解析为CommonJS要使用ESModule有两种方式</p><ul><li>所有ESModule的后缀名都使用<code>.mjs</code>并且不可省略 <ul><li>这样引擎在解析到<code>.mjs</code>结尾的文件时将按照ESModule的规则解析其导入导出关系</li></ul></li><li><code>package.json</code>中的<code>type</code>字段修改为<code>module</code><ul><li>此时项目中所有<code>.js</code>文件都将被作为ESModule模块解析</li><li>要在此项目中使用CommonJS则需要将后缀名修改为<code>.cjs</code></li></ul></li></ul><h4 id="解读package-json中的字段" tabindex="-1">解读<code>package.json</code>中的字段 <a class="header-anchor" href="#解读package-json中的字段" aria-hidden="true">#</a></h4><ul><li><p><code>main</code>字段</p><ul><li>指定一个npm包的<code>main</code>字段为一个JS模块</li><li>当我们从其他位置通过<code>import { something } from &#39;es-module-package&#39;</code>导入时</li><li>Node.js将从<code>main</code>字段指定的模块查找导出内容</li></ul></li><li><p><code>exports</code>字段</p><ul><li><code>exports</code>字段优先级高于<code>main</code>字段,它具有多种用法:</li><li>子目录别名 <ul><li>假设如是定义<code>exports</code>字段:<code>exports: { &quot;./submodule&quot;: &quot;./src/submodule.js&quot; }</code></li><li>当执行<code>import submodule from &#39;es-module-package/submodule&#39;</code>时,会按照以下路径查找模块:</li><li><code>./node_modules/es-module-package/src/submodule.js</code></li></ul></li><li><code>main</code>的别名</li><li>条件加载</li></ul></li></ul><p>参考:<a href="https://es6.ruanyifeng.com/#docs/module-loader#package-json-%E7%9A%84-exports-%E5%AD%97%E6%AE%B5" target="_blank" rel="noreferrer">package.json 的 exports 字段</a></p></div></div></main><!--[--><!--]--><footer class="VPDocFooter" data-v-30dabfe4 data-v-cc0f9778><div class="edit-info" data-v-cc0f9778><div class="edit-link" data-v-cc0f9778><a class="VPLink link edit-link-button" href="https://github.com/ZiuChen/ZiuChen.github.io/edit/main/docs/note/Front-end Engineering.md" target="_blank" rel="noreferrer" data-v-cc0f9778 data-v-8dd200cc><!--[--><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="edit-link-icon" data-v-cc0f9778><path d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z"></path><path d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z"></path></svg> Edit this page on GitHub<!--]--><!----></a></div><div class="last-updated" data-v-cc0f9778><p class="VPLastUpdated" data-v-cc0f9778 data-v-de6a4e1f>Updated Date: <time datetime="2023-02-11T17:51:22.000Z" data-v-de6a4e1f></time></p></div></div><div class="prev-next" data-v-cc0f9778><div class="pager" data-v-cc0f9778><a class="pager-link prev" href="/note/JavaScriptEnhanced.html" data-v-cc0f9778><span class="desc" data-v-cc0f9778>Previous page</span><span class="title" data-v-cc0f9778>JavaScript进阶</span></a></div><div class="has-prev pager" data-v-cc0f9778><!----></div></div></footer><!--[--><!--]--></div></div></div></div></div><footer class="VPFooter has-sidebar" data-v-3af881ed data-v-8b655284><div class="container" data-v-8b655284><p class="message" data-v-8b655284>Released under the MIT License.</p><p class="copyright" data-v-8b655284>Copyright © 2019-present Ziu Chen</p></div></footer><!--[--><!--]--></div></div>
<script>__VP_HASH_MAP__ = JSON.parse("{\"article_一文读懂事件冒泡与事件捕获.md\":\"1fae2ef6\",\"article_深入vue3源码看看vue.use后究竟发生了什么.md\":\"e9cb7103\",\"index.md\":\"c44d84f3\",\"article_【2023】青训营 - 前端练习题汇总解析.md\":\"08daa7cb\",\"article_一文读懂伪类与伪元素.md\":\"f13fdfe2\",\"article_从0实现一个年度报告.md\":\"7889052b\",\"article_一文读懂函数中this指向问题.md\":\"3d26963f\",\"article_彻底搞懂对象的数据属性描述符、存储属性描述符.md\":\"a79489f6\",\"article_深入理解proxy与reflect.md\":\"29b5e84c\",\"article_深入理解浏览器缓存机制.md\":\"6cb4dc3b\",\"article_深入理解浏览器运行原理.md\":\"afa95ccd\",\"note_javascript.md\":\"274c2492\",\"note_front-end engineering.md\":\"3f047f08\",\"note_css.md\":\"7c0e34d6\",\"project_smartwordbreak_log_index.md\":\"dfc020de\",\"project_smartwordbreak_statement_index.md\":\"db452751\",\"self_index.md\":\"dd9eeb1d\",\"works_contribution.md\":\"fb91e133\",\"works_opensource.md\":\"48524035\",\"project_clipboardmanager_vip_index.md\":\"440f01a9\",\"project_clipboardmanager_statement_index.md\":\"d5066f69\",\"project_clipboardmanager_guide_index.md\":\"81ab619b\",\"project_clipboardmanager_log_index.md\":\"0a410da9\",\"project_smartwordbreak_index.md\":\"d5edfcd7\",\"project_clipboardmanager_index.md\":\"beb258ff\",\"note_javascriptenhanced.md\":\"ded85c98\"}")</script>
<script type="module" async src="/assets/app.f4e2d6d1.js"></script>
</body>
</html>