<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          帶你深入了解 Module

          共 8225字,需瀏覽 17分鐘

           ·

          2021-03-10 10:20

          模塊介紹

          當(dāng)我們的應(yīng)用程序變大時,我們想要把它分割成多個文件,也就是所謂的“模塊”。一個模塊可以包含一個用于特定目的的類或函數(shù)庫。

          很長一段時間以來,JavaScript都沒有語言級的模塊語法。這不是問題,因為最初的腳本很小很簡單,所以沒有必要。

          但最終腳本變得越來越復(fù)雜,因此社區(qū)發(fā)明了各種方法來將代碼組織到模塊中,以及根據(jù)需要加載模塊的特殊庫。

          • AMD——最古老的模塊系統(tǒng)之一,最初由require.js庫實現(xiàn)。

          • CommonJS -為Node.js服務(wù)器創(chuàng)建的模塊系統(tǒng)。

          • UMD -另一個模塊系統(tǒng),建議作為一個通用的,兼容AMD和CommonJS。

          現(xiàn)在所有這些慢慢地成為歷史的一部分,但我們?nèi)匀豢梢栽诠爬系哪_本中找到它們。

          語言級模塊系統(tǒng)于2015年出現(xiàn)在標(biāo)準(zhǔn)中,后來逐漸演變,現(xiàn)在所有主流瀏覽器和Node.js都支持它。因此,我們將從現(xiàn)在開始學(xué)習(xí)現(xiàn)代JavaScript模塊。

          什么是模塊

          模塊只是一個文件。一個腳本就是一個模塊。就這么簡單。

          模塊可以相互加載,并使用特殊的指令導(dǎo)出和導(dǎo)入來交換功能,從一個模塊調(diào)用另一個模塊的函數(shù):

          • export 關(guān)鍵字標(biāo)簽變量和函數(shù),這些變量和函數(shù)應(yīng)該可以從當(dāng)前模塊外部訪問。

          • import 允許從其他模塊導(dǎo)入功能。

          例如,如果我們有一個文件sayHi.js導(dǎo)出一個函數(shù):

          // ?? sayHi.js
          export function sayHi(user{
            alert(`Hello, ${user}!`);
          }

          然后另一個文件可以導(dǎo)入并使用它:

          // ?? main.js
          import {sayHi} from './sayHi.js';

          alert(sayHi); // function...
          sayHi('John'); // Hello, John!

          import指令通過相對于當(dāng)前文件的path ./sayHi.js加載模塊,并將導(dǎo)出的函數(shù)sayHi賦給相應(yīng)的變量。

          讓我們在瀏覽器中運(yùn)行這個示例。

          由于模塊支持特殊的關(guān)鍵字和特性,所以我們必須通過屬性

          sayHi.js

          export function sayHi(user{
            return `Hello, ${user}!`;
          }

          index.html

          <!doctype html>
          <script type="module">
            import {sayHi} from './say.js';

            document.body.innerHTML = sayHi('John');
          </script>

          核心模塊功能

          與“常規(guī)”腳本相比,模塊有什么不同?

          有一些核心特性,對瀏覽器和服務(wù)器端JavaScript都有效。

          use strict

          默認(rèn)情況下,模塊總是使用嚴(yán)格模式的。例如,給未聲明的變量賦值會產(chǎn)生錯誤。

          <script type="module">
            a = 5// error
          </script>

          塊級作用域

          每個模塊都有自己的頂級作用域。換句話說,一個模塊中的頂級變量和函數(shù)在其他腳本中看不到。

          在下面的例子中,導(dǎo)入了兩個腳本,hello.js嘗試使用user.js中聲明的user變量:

          user.js

          let user = "John";

          hello.js

          alert(user); // no such variable (each module has independent variables)

          index.html

          <!doctype html>
          <script type="module" src="user.js"></script>
          <script type="module" src="hello.js"></script>

          模塊應(yīng)該導(dǎo)出它們希望從外部訪問的內(nèi)容,并導(dǎo)入它們需要的內(nèi)容。

          因此,我們應(yīng)該將user.js導(dǎo)入到hello.js中,并從中獲取所需的功能,而不是依賴全局變量。

          這是正確的變體:

          user.js

          export let user = "John";

          hello.js

          import {user} from './user.js';

          document.body.innerHTML = user; // John

          index.html

          <!doctype html>
          <script type="module" src="hello.js"></script>

          在瀏覽器中,每個<script type="module">對象都有獨立的頂級作用域

          <script type="module">
            // The variable is only visible in this module script
            let user = "John";
          </script>

          <script type="module">
            alert(user); /
          / Error: user is not defined
          </
          script>

          如果我們真的需要創(chuàng)建一個窗口級全局變量,我們可以顯式地將它分配給window,并作為window.user訪問。但這是一個需要充分理由的例外。

          模塊代碼只在第一次導(dǎo)入時才被求值

          如果同一個模塊被導(dǎo)入到其他多個位置,它的代碼只在第一次執(zhí)行,然后導(dǎo)出將被交給所有導(dǎo)入器。

          這有重要的后果。讓我們來看看他們的例子:

          首先,如果執(zhí)行一個模塊代碼會帶來副作用,比如顯示一條消息,那么多次導(dǎo)入它只會觸發(fā)一次-第一次:

          // ?? alert.js
          alert("Module is evaluated!");
          // Import the same module from different files

          // ?? 1.js
          import `./alert.js`// Module is evaluated!

          // ?? 2.js
          import `./alert.js`// (shows nothing)

          在實踐中,頂級模塊代碼主要用于初始化、內(nèi)部數(shù)據(jù)結(jié)構(gòu)的創(chuàng)建,如果我們想要某些東西可重用—導(dǎo)出它。

          現(xiàn)在,一個更高級的例子。

          比方說,一個模塊導(dǎo)出了一個對象:

          // ?? admin.js
          export let admin = {
            name"John"
          };

          如果從多個文件導(dǎo)入此模塊,則只在第一次評估該模塊,創(chuàng)建admin對象,然后傳遞給所有進(jìn)一步的導(dǎo)入器。

          所有的導(dǎo)入器都只有一個admin對象:

          // ?? 1.js
          import {admin} from './admin.js';
          admin.name = "Pete";

          // ?? 2.js
          import {admin} from './admin.js';
          alert(admin.name); // Pete

          // Both 1.js and 2.js imported the same object
          // Changes made in 1.js are visible in 2.js

          所以,讓我們重申一下——這個模塊只執(zhí)行一次。導(dǎo)出將生成,然后它們將在導(dǎo)入器之間共享,因此,如果管理對象發(fā)生了更改,其他模塊將看到這一點。

          這樣的行為允許我們在第一次導(dǎo)入時配置模塊。我們可以設(shè)置它的屬性一次,然后在進(jìn)一步導(dǎo)入時,它就準(zhǔn)備好了。

          例如,admin.js模塊可能提供某些功能,但希望憑據(jù)從外部進(jìn)入admin對象:

          // ?? admin.js
          export let admin = { };

          export function sayHi({
            alert(`Ready to serve, ${admin.name}!`);
          }

          在init.js 在應(yīng)用程序的第一個腳本中,我們設(shè)置admin.name。然后所有人都會看到它,包括從admin.js內(nèi)部調(diào)用:

          // ?? init.js
          import {admin} from './admin.js';
          admin.name = "Pete";

          另一個模塊也可以看到admin.name:

          // ?? other.js
          import {admin, sayHi} from './admin.js';

          alert(admin.name); // Pete

          sayHi(); // Ready to serve, Pete!

          import.meta

          導(dǎo)入的對象。元包含關(guān)于當(dāng)前模塊的信息。

          它的內(nèi)容取決于環(huán)境。在瀏覽器中,它包含腳本的url,或者當(dāng)前網(wǎng)頁的url,如果在HTML中:

          <script type="module">
            alert(import.meta.url); // script url (url of the html page for an inline script)
          </script>

          In a module, “this” is undefined

          這是一個小特性,但是為了完整性,我們應(yīng)該提到它。

          在模塊中,這是未定義的頂層。

          與非模塊腳本相比,它是一個全局對象:

          <script>
            alert(this); // window
          </script>

          <script type="module">
            alert(this); /
          / undefined
          </
          script>

          瀏覽器 特定功能

          與常規(guī)的腳本相比,使用type="module"的腳本還有一些特定于瀏覽器的差異。

          如果您是第一次閱讀,或者您沒有在瀏覽器中使用JavaScript,那么您可能想要跳過這一部分。

          模塊腳本被延遲

          <script type="module">
            alert(typeof button); // object: the script can 'see' the button below
            // as modules are deferred, the script runs after the whole page is loaded
          </script>

          Compare to regular script below:

          <script>
            alert(typeof button); /
          / button is undefined, the script can't see elements below
            /
          / regular scripts run immediately, before the rest of the page is processed
          </
          script>

          <button id="button">Button</button>

          請注意:第二個腳本實際上在第一個腳本之前運(yùn)行!首先是undefined,然后是object。

          這是因為模塊被延遲了,所以我們等待文檔被處理。常規(guī)腳本立即運(yùn)行,所以我們首先看到它的輸出。

          當(dāng)使用模塊時,我們應(yīng)該注意HTML頁面在加載時顯示,JavaScript模塊在加載后運(yùn)行,所以用戶可能在JavaScript應(yīng)用程序準(zhǔn)備好之前看到頁面。有些功能可能還不能工作。我們應(yīng)該設(shè)置“加載指示符”,否則將確保訪問者不會被混淆。

          異步在內(nèi)聯(lián)腳本上工作

          對于非模塊腳本,async屬性只對外部腳本有效。異步腳本在準(zhǔn)備好后立即運(yùn)行,獨立于其他腳本或HTML文檔。

          對于模塊腳本,它也適用于內(nèi)聯(lián)腳本。

          例如,下面的內(nèi)聯(lián)腳本是異步的,所以它不等待任何東西。

          它執(zhí)行導(dǎo)入(fetch ./analytics.js)并在準(zhǔn)備好時運(yùn)行,即使HTML文檔還沒有完成,或者其他腳本仍在等待中。

          這對于不依賴于任何東西的功能來說是很好的,比如計數(shù)器、廣告、文檔級事件偵聽器。

          <!-- all dependencies are fetched (analytics.js), and the script runs -->
          <!-- doesn't wait for the document or other <script> tags -->
          <script async type="module">
            import {counter} from '
          ./analytics.js';

            counter.count();
          </script>

          外部腳本

          有type="module"的外部腳本有兩個不同:

          具有相同src的外部腳本只運(yùn)行一次:

          <!-- the script my.js is fetched and executed only once -->
          <script type="module" src="my.js"></script>
          <script type="module" src="my.js"></script>

          從另一個來源(例如另一個站點)獲取的外部腳本需要CORS頭,如“獲取:跨來源請求”章節(jié)所述。換句話說,如果一個模塊腳本是從另一個來源獲取的,遠(yuǎn)程服務(wù)器必須提供一個頭部Access-Control-Allow-Origin允許獲取。

          <!-- another-site.com must supply Access-Control-Allow-Origin -->
          <!-- otherwise, the script won't execute -->
          <script type="module" src="http://another-site.com/their.js"></script>

          不允許出現(xiàn)裸模塊

          在瀏覽器中,import必須獲得一個相對URL或絕對URL。沒有任何路徑的模塊稱為“裸”模塊。這樣的模塊是不允許導(dǎo)入的。

          例如,此導(dǎo)入無效:

          import {sayHi} from 'sayHi'// Error, "bare" module
          // the module must have a path, e.g. './sayHi.js' or wherever the module is

          Compatibility, “nomodule”

          舊的瀏覽器不理解type="module"。未知類型的腳本將被忽略。對于它們,可以使用nomodule屬性提供回退:

          <script type="module">
            alert("Runs in modern browsers");
          </script>

          <script nomodule>
            alert("Modern browsers know both type=module and nomodule, so skip this")
            alert("Old browsers ignore script with unknown type=module, but execute this.");
          </
          script>


          瀏覽 149
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  最新国产精品 | 看免费毛片!!! | 青娱乐在线国产视频 | 成人亚洲精品777777大片 | 久留影院 |