首頁 >web前端 >js教程 >了解ES6模塊

了解ES6模塊

Lisa Kudrow
Lisa Kudrow原創
2025-02-15 10:57:11436瀏覽

Understanding ES6 Modules

ES6 模塊:現代 JavaScript 的模塊化方案

本文探討 ES6 模塊,並展示如何在轉譯器的幫助下使用它們。幾乎所有語言都有模塊的概念——一種在另一個文件中包含已聲明功能的方法。通常,開發人員會創建一個封裝的代碼庫,負責處理相關的任務。該庫可以被應用程序或其他模塊引用。其優勢在於:

  1. 代碼可以拆分成更小的、自包含功能的文件。
  2. 相同的模塊可以在任意數量的應用程序之間共享。
  3. 理想情況下,模塊無需被其他開發人員檢查,因為它們已被證明有效。
  4. 引用模塊的代碼知道它是一個依賴項。如果模塊文件被更改或移動,問題會立即顯現。
  5. 模塊代碼(通常)有助於消除命名衝突。模塊 1 中的函數 x() 不會與模塊 2 中的函數 x() 衝突。可以使用命名空間等選項,使調用變為 module1.x() 和 module2.x()。

JavaScript 中的模塊在哪裡?

幾年前開始 Web 開發的任何人都會驚訝地發現 JavaScript 中沒有模塊的概念。無法直接引用或包含一個 JavaScript 文件到另一個文件中。因此,開發人員求助於其他方法。

多種 HTML <p> </p> <ul></ul>

  • 然而,這並非理想方案:
  • 每個腳本都會發起一個新的 HTTP 請求,這會影響頁面性能。 HTTP/2 在一定程度上緩解了這個問題,但它無助於引用其他域(如 CDN)上的腳本。
  • 每個腳本在其運行期間都會暫停進一步的處理。
  • 依賴項管理是一個手動過程。在上面的代碼中,如果 lib1.js 引用了 lib2.js 中的代碼,則代碼會失敗,因為它尚未加載。這可能會破壞進一步的 JavaScript 處理。

    除非使用適當的模塊模式,否則函數可能會覆蓋其他函數。早期的 JavaScript 庫因使用全局函數名或覆蓋原生方法而臭名昭著。

    腳本合併

    <code class="language-html"></code>
    解決多個

    或者內聯:

    模塊只解析一次,無論它們在頁面或其他模塊中被引用多少次。

    <p> <strong> </strong></p>

    服務器注意事項

    <script> 标签</script>

    HTML 可以使用多个 <script></script> 标签加载任意数量的 JavaScript 文件:

    <code class="language-html"><script src="lib1.js"></script>模塊必須使用 MIME 類型 application/javascript 提供服務。大多數服務器會自動執行此操作,但要注意動態生成的腳本或 .mjs 文件(請參閱下面的 Node.js 部分)。常規 <script src="lib2.js"></script><script src="core.js"></script>
    <script>console.log('inline code');</script><script></script></code> 标签问题的一种方法是将所有 JavaScript 文件合并成一个大型文件。这解决了一些性能和依赖项管理问题,但可能会导致手动构建和测试步骤。
    <p><strong>模块加载器</strong></p>
    <p>RequireJS 和 SystemJS 等系统提供了一个库,用于在运行时加载和命名其他 JavaScript 库。模块在需要时使用 Ajax 方法加载。这些系统有所帮助,但对于大型代码库或添加标准 <code><script></script></code> 标签的网站来说,可能会变得复杂。</p>
    <p><strong>模块打包器、预处理器和转译器</strong></p>
    <p>打包器引入了编译步骤,以便在构建时生成 JavaScript 代码。代码经过处理以包含依赖项并生成单个 ES5 跨浏览器兼容的合并文件。流行的选项包括 Babel、Browserify、webpack 以及更通用的任务运行器,如 Grunt 和 Gulp。</p>
    <p>JavaScript 构建过程需要一些努力,但也有好处:</p>
    
    • 处理是自动化的,因此人为错误的可能性较小。
    • 进一步的处理可以整理代码、删除调试命令、缩小结果文件等。
    • 转译允许您使用替代语法,如 TypeScript 或 CoffeeScript。

    ES6 模块

    上述选项引入了各种相互竞争的模块定义格式。广泛采用的语法包括:

    • CommonJS——Node.js 中使用的 module.exports 和 require 语法
    • 异步模块定义 (AMD)
    • 通用模块定义 (UMD)

    因此,在 ES6 (ES2015) 中提出了单一的原生模块标准。

    ES6 模块内部的所有内容默认情况下都是私有的,并且在严格模式下运行(不需要“use strict”)。公共变量、函数和类使用 export 导出。例如:

    <code class="language-javascript">// lib.js
    export const PI = 3.1415926;
    export function sum(...args) {
      log('sum', args);
      return args.reduce((num, tot) => tot + num);
    }
    export function mult(...args) {
      log('mult', args);
      return args.reduce((num, tot) => tot * num);
    }
    // 私有函数
    function log(...msg) {
      console.log(...msg);
    }</code>

    或者,可以使用单个 export 语句。例如:

    <code class="language-javascript">// lib.js
    const PI = 3.1415926;
    
    function sum(...args) {
      log('sum', args);
      return args.reduce((num, tot) => tot + num);
    }
    
    function mult(...args) {
      log('mult', args);
      return args.reduce((num, tot) => tot * num);
    }
    
    // 私有函数
    function log(...msg) {
      console.log(...msg);
    }
    
    export { PI, sum, mult };</code>

    然后使用 import 将模块中的项目导入到另一个脚本或模块中:

    <code class="language-javascript">// main.js
    import { sum } from './lib.js';
    
    console.log(sum(1, 2, 3, 4)); // 10</code>

    在这种情况下,lib.js 与 main.js 在同一个文件夹中。可以使用绝对文件引用(以 / 开头)、相对文件引用(以 ./ 或 ../ 开头)或完整 URL。可以一次导入多个项目:

    <code class="language-javascript">import { sum, mult } from './lib.js';
    
    console.log(sum(1, 2, 3, 4));  // 10
    console.log(mult(1, 2, 3, 4)); // 24</code>

    并且可以为导入指定别名以解决命名冲突:

    <code class="language-javascript">import { sum as addAll, mult as multiplyAll } from './lib.js';
    
    console.log(addAll(1, 2, 3, 4));      // 10
    console.log(multiplyAll(1, 2, 3, 4)); // 24</code>

    最后,可以通过提供命名空间来导入所有公共项目:

    <code class="language-javascript">import * as lib from './lib.js';
    
    console.log(lib.PI);            // 3.1415926
    console.log(lib.sum(1, 2, 3, 4));  // 10
    console.log(lib.mult(1, 2, 3, 4)); // 24</code>

    在浏览器中使用 ES6 模块

    在撰写本文时,ES6 模块受 Chromium 系浏览器 (v63+)、Safari 11+ 和 Edge 16+ 支持。Firefox 支持将在版本 60 中到来(在 v58+ 中位于 about:config 标志之后)。使用模块的脚本必须通过在 <script></script> 标签中设置 type="module" 属性来加载。例如:

    模塊回退<script></script> 标签可以获取其他域上的脚本,但模块是使用跨域资源共享 (CORS) 获取的。因此,不同域上的模块必须设置适当的 HTTP 标头,例如 Access-Control-Allow-Origin: *。
    

    最后,除非在 <script></script> 标签中添加 crossorigin="use-credentials" 属性并且响应包含标头 Access-Control-Allow-Credentials: true,否则模块不会发送 Cookie 或其他标头凭据。

    模块执行被延迟

    <script></script> 标签的 defer 属性会延迟脚本执行,直到文档加载并解析完毕。模块(包括内联脚本)默认情况下会延迟。示例:

    <!-- 运行在第二位 -->
    <script type="module">
      // 执行某些操作...
    </script>
    <script defer src="c.js"></script>不支持模塊的瀏覽器不會運行 type="module" 腳本。可以使用 nomodule 屬性提供一個回退腳本,模塊兼容的瀏覽器會忽略該屬性。例如:<script src="a.js"></script><pre class="brush:php;toolbar:false">&lt;code class=&quot;language-html&quot;&gt;&lt;/code&gt;</pre>
    <p><strong>您應該在瀏覽器中使用模塊嗎? </strong></p>
    <p>瀏覽器支持正在增長,但現在切換到 ES6 模塊可能還為時過早。目前,最好使用模塊打包器來創建一個在任何地方都能工作的腳本。 </p>
    <p><strong>在 Node.js 中使用 ES6 模塊</strong></p>
    <p>Node.js 在 2009 年發佈時,任何運行時不提供模塊都是不可想像的。採用了 CommonJS,這意味著可以開發 Node 包管理器 npm。從那時起,使用量呈指數級增長。 CommonJS 模塊的編碼方式與 ES2015 模塊類似。使用 module.exports 而不是 export:</p>
    <pre class="brush:php;toolbar:false">&lt;code class=&quot;language-html&quot;&gt;
    &lt;/code&gt;</pre>
    <p>使用 require(而不是 import)將此模塊導入到另一個腳本或模塊中:</p>
    <pre class="brush:php;toolbar:false">&lt;code class=&quot;language-javascript&quot;&gt;// lib.js
    const PI = 3.1415926;
    
    function sum(...args) {
      log('sum', args);
      return args.reduce((num, tot) =&gt; tot + num);
    }
    
    function mult(...args) {
      log('mult', args);
      return args.reduce((num, tot) =&gt; tot * num);
    }
    
    // 私有函数
    function log(...msg) {
      console.log(...msg);
    }
    
    module.exports = { PI, sum, mult };&lt;/code&gt;</pre>
    <p>require 也可以導入所有項目:</p>
    <pre class="brush:php;toolbar:false">&lt;code class=&quot;language-javascript&quot;&gt;const { sum, mult } = require('./lib.js');
    
    console.log(sum(1, 2, 3, 4));  // 10
    console.log(mult(1, 2, 3, 4)); // 24&lt;/code&gt;</pre>
    <p>那麼,在 Node.js 中實現 ES6 模塊很容易,對嗎? <em>不對</em>。 ES6 模塊在 Node.js 9.8.0  中位於標誌之後,並且至少要到版本 10 才會完全實現。雖然 CommonJS 和 ES6 模塊具有相似的語法,但它們的工作方式根本不同:</p>
    <ul>
    <li>ES6 模塊在執行代碼之前預先解析以解析進一步的導入。 </li>
    <li>CommonJS 模塊在執行代碼時按需加載依賴項。 </li>
    </ul>
    <p>在上面的示例中這沒有區別,但請考慮以下 ES2015 模塊代碼:</p>
    <pre class="brush:php;toolbar:false">&lt;code class=&quot;language-javascript&quot;&gt;const lib = require('./lib.js');
    
    console.log(lib.PI);            // 3.1415926
    console.log(lib.sum(1, 2, 3, 4));  // 10
    console.log(lib.mult(1, 2, 3, 4)); // 24&lt;/code&gt;</pre>
    <p>ES2015 的輸出:</p>
    <pre class="brush:php;toolbar:false">&lt;code class=&quot;language-javascript&quot;&gt;// ES2015 模块
    
    // ---------------------------------
    // one.js
    console.log('running one.js');
    import { hello } from './two.js';
    console.log(hello);
    
    // ---------------------------------
    // two.js
    console.log('running two.js');
    export const hello = 'Hello from two.js';&lt;/code&gt;</pre>
    <p>使用 CommonJS 編寫的類似代碼:</p>
    <pre class="brush:php;toolbar:false">&lt;code&gt;running two.js
    running one.js
    Hello from two.js&lt;/code&gt;</pre>
    <p>CommonJS 的輸出:</p>
    <pre class="brush:php;toolbar:false">&lt;code class=&quot;language-javascript&quot;&gt;// CommonJS 模块
    
    // ---------------------------------
    // one.js
    console.log('running one.js');
    const hello = require('./two.js');
    console.log(hello);
    
    // ---------------------------------
    // two.js
    console.log('running two.js');
    module.exports = 'Hello from two.js';&lt;/code&gt;</pre>
    <p>執行順序在某些應用程序中可能至關重要,如果在同一個文件中混合使用 ES2015 和 CommonJS 模塊會發生什麼?為了解決這個問題,Node.js 僅允許在擴展名為 .mjs 的文件中使用 ES6 模塊。擴展名為 .js 的文件將默認為 CommonJS。這是一個簡單的選項,它消除了大部分複雜性,並且應該有助於代碼編輯器和代碼檢查器。 </p>
    <p><strong>您應該在 Node.js 中使用 ES6 模塊嗎? </strong></p>
    <p>ES6 模塊僅在 Node.js v10 及更高版本(於 2018 年 4 月發布)中實用。轉換現有項目不太可能帶來任何好處,並且會使應用程序與早期版本的 Node.js 不兼容。對於新項目,ES6 模塊提供了一種 CommonJS 的替代方案。語法與客戶端編碼相同,並且可能為同構 JavaScript 提供更簡單的途徑,同構 JavaScript 可以在瀏覽器或服務器上運行。 </p>
    <p><strong>模塊混戰</strong></p>
    <p>標準化的 JavaScript 模塊系統花了多年時間才出現,並且花了更長時間才實現,但問題已經得到糾正。從 2018 年年中開始,所有主流瀏覽器和 Node.js 都支持 ES6 模塊,儘管在每個人都升級時應該預期會有一個切換延遲。今天學習 ES6 模塊,以便在明天從您的 JavaScript 開發中受益。 </p>
    <p><strong>關於 ES6 模塊的常見問題解答 (FAQ)</strong></p>
    <p><strong>(此處省略了原文檔中的FAQ部分,因為已經對全文進行了充分的偽原創)</strong></p>

    以上是了解ES6模塊的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn