成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

快速了解JavaScript的模塊

開發 前端
隨著現代 JavaScript 開發 Web 應用變得復雜,命名沖突和依賴關系也變得難以處理,因此需要模塊化。

概述

[[436275]]

隨著現代 JavaScript 開發 Web 應用變得復雜,命名沖突和依賴關系也變得難以處理,因此需要模塊化。而引入模塊化,可以避免命名沖突、方便依賴關系管理、提高了代碼的復用性和和維護性,因此,在 JavaScript 沒有模塊功能的前提下,只能通過第三方規范實現模塊化:

  • CommonJS:同步模塊定義,用于服務器端。
  • AMD:異步模塊定義, 用于瀏覽器端。
  • CMD:異步模塊定義,用于瀏覽器端。
  • UMD:統一 COmmonJS 和 AMD 模塊化方案的定義。

它們都是基于 JavaScript 的語法和詞法特性 “偽造” 出類似模塊的行為。而 TC-39 在 ECMAScript 2015 中加入了模塊規范,簡化了上面介紹的模塊加載器,原生意味著可以取代上述的規范,成為瀏覽器和服務器通用的模塊解決方案,比使用庫更有效率。而 ES6 的模塊化的設計目標:

  • 像 CommonJS 一樣簡單的語法。
  • 模塊必須是靜態的結構
  • 支持模塊的 異步加載 和 同步加載,能同時用在 server 和 client 端
  • 支持模塊加載的 ‘靈活配置’
  • 更好地支持模塊之間的循環引用
  • 擁有語言層面的支持,超越 CommonJS 和 AMD

ECMAScript 在 2015 年開始支持模塊標準,此后逐漸發展,現已經得到了所有主流瀏覽器的支持。ECMAScript 2015 版本也被稱為 ECMAScript 6。

模塊

ES6 模塊借用了 CommonJS 和 AMD 的很多優秀特性,如下所示:

  • 模塊代碼只在加載后執行。
  • 模塊只能加載一次。
  • 模塊是單例。
  • 模塊可以定義公共接口,其他模塊可以基于這個公共接口觀察和交互。
  • 模塊可以請求加載其他模塊。
  • 支持循環依賴。

ES6 模塊系統也增加了一些新行為。

  • ES6 模塊默認在嚴格模式下執行。
  • ES6 模塊不共享全局命名空間。
  • 模塊頂級 this 的值是 undefined;常規腳本中是 window。
  • 模塊中的 var 聲明不會添加到 window 對象。
  • ES6 模塊是異步加載和執行的。

瀏覽器運行時在知道應該把某個文件當成模塊時,會有條件地按照上述 ES6 模塊行為來施加限制。與 <script type="module"> 關聯或者通過 import 語句加載的 JavaScript 文件會被認定為模塊。

 

 

導出

ES6 模塊內部的所有變量,外部無法獲取,因此提供了 export 關鍵字從模塊中導出實時綁定的函數、對象或原始值,這樣其他程序可以通過 import 關鍵字使用它們。export 支持兩種導出方式:命名導出和默認導出。不同的導出方式對應不同的導入方式。

在 ES6 模塊中,無論是否聲明 "use strict;" 語句,默認情況下模塊都是在嚴格模式下運行。export 語句不能用在嵌入式腳本中。

命名導出

通過在聲明的前面加上 export 關鍵字,一個模塊可以導出多個內容。這些導出的內容通過名字區分,被稱為命名導出。

 

  1. // 導出單個特性(可以導出 var,let,const) 
  2. export let name = "小明"
  3. export function sayHi(name) { 
  4.     console.log(`Hello, ${name}!`); 
  5. export class Sample { 
  6.     ... 

 

或者導出事先定義的特性

 

  1. let name = "小明"
  2. const age = 18; 
  3. function sayHi(name) { 
  4.     console.log(`Hello, ${name}!`); 
  5. export {name, age, sayHi} 

 

導出時也可以指定別名,別名必須在 export 子句的大括號語法中指定。因此,聲明值、導出值和未導出值提供別名不能在一行完成。

 

  1. export {name as username, age, sayHi} 

但導出語句必須在模塊頂級,不能嵌套在某個塊中:

 

  1. // 允許 
  2. export ... 
  3. // 不允許 
  4. if (condition) { 
  5.     export ... 

 

默認導出

默認導出就好像模塊與被導出的值是一回事。默認導出使用 default 關鍵字將一個值聲明為默認導出,每個模塊只能有一個默認導出。重復的默認導出會導致 SyntaxError。如下所示:

 

  1. // 導出事先定義的特性作為默認值 
  2. export default { 
  3.     name"Xiao Ming"
  4.     age: 18, 
  5.     sex: "boy" 
  6. }; 
  7. export {sayHi as default}    // ES 6 模塊會識別作為別名提供的 default 關鍵字。此時,雖然對應的值是使用命名語法導出的,實際上則會稱為默認導出 等同于 export default function sayHi() {} 
  8. // 導出單個特性作為默認值 
  9. export default function () {...} 
  10. export default class {...} 

ES6 規范對不同形式的 export 語句中可以使用什么不可以使用什么規定了限制。某些形式允許聲明和賦值,某些形式只允許表達式,而某些形式則只允許簡單標識符。注意,有的形式使用了分號,有的則沒有。

下面列出幾種會導致錯誤的 export 形式:

  1. // 會導致錯誤的不同形式: 
  2. // 行內默認導出中不能出現變量聲明 
  3. export default const name = '小劉'
  4. // 只有標識符可以出現在export 子句中 
  5. export { 123 as name } 
  6. // 別名只能在export 子句中出現 
  7. export const name = '小紅' as uname; 

 

注意:聲明、賦值和導出標識符最好分開。這樣不容易搞錯了,同時也可以讓 export 語句集中在一塊。而且,沒有被 export 關鍵字導出的變量、函數或類會在模塊內保持私有。

模塊重定向

模塊導入的值還可以再次導出,這樣的話,可以在父模塊集中多個模塊的多個導出。可以使用 export from 語法實現:

 

  1. export {default as m1, namefrom './module1.js' 
  2. // 等效于 
  3. import {default as m1, namefrom "./module1.js" 
  4. export {m1, name

 

外部模塊的默認導出也可以重用為當前模塊的默認導出:

 

  1. export { default } from './module1.js'

也可以在重新導出時,將導入模塊修改為默認導出,如下所示:

 

  1. export { name as default } from './module1.js'

而想要將所有命名導出可以使用如下語法:

 

  1. export * from './module1.js'

該語法會忽略默認導出。但這種語法也要注意導出名稱是否沖突。如下所示:

 

  1. // module1.js 
  2. export const name = "module1:name"
  3. // module2.js 
  4. export * from './mudule1.js' 
  5. export const name = "module2:name"
  6. // index.js 
  7. import { name } from './module2.js'
  8. console.log(name); // module2:name 

 

最終輸出的是 module2.js 中的值,這個 “重寫” 是靜默發生的。

導入

使用 export 關鍵字定義了模塊的對外接口以后,其它模塊就能通過 import 關鍵字加載這個模塊了。但與 export 類似,import 也必須出現在模塊的頂級:

 

  1. // 允許 
  2. import ... 
  3. // 不允許 
  4. if (condition) { 
  5.     import ... 

 

模塊標識符可以是相對于當前模塊的相對路徑,也可以是指向模塊文件的絕對路徑。它必須是純字符串,不能是動態計算的結果。例如,不能是拼接的字符串。

當使用 export 命名導出時,可以使用 * 批量獲取并賦值給保存導出集合的別名,而無須列出每個標識符:

 

  1. const name = "Xiao Ming", age = 18, sex = "boy"
  2. export {name, age, sex} 
  3.  
  4. // 上面的命名導出可以使用如下形式導入(上面的代碼是在 module1.js 模塊中) 
  5. import * as Sample from "./module1.js" 
  6. console.log(`My name is ${Sample.name}, A ${Sample.sex},${Sample.age} years old.`); 

 

也可以指名導入,只需要把名字放在 {} 中即可:

 

  1. import {name, sex as s, age} from "./module1.js"
  2. console.log(`My name is ${name}, A ${s},${age} years old.`); 

 

import 引入是采用的 Singleton 模式,多次使用 import 引入同一個模塊時,只會引入一次該模塊的實例:

 

  1. import {name, age} from "./module1.js"
  2. import {sex as s} from "./module1.js"
  3. // 等同于,并且只會引入一個 module1.js 實例 
  4. import {name, sex as s, age} from "./module1.js"

 

而使用默認導出的話,可以使用 default 關鍵字并提供別名來導入,也可以直接使用標識符就是默認導出的別名導入:

 

  1. import {default as Sample} from "./module1.js" 
  2. // 與下面的方式等效 
  3. import Sample from "./module1.js" 

 

而模塊中同時有命名導出和默認導出,可以在 import 語句中同時導入。下面三種方式都等效。

 

  1. import Sample, {sayHi} from "./module1.js" 
  2. import {default as Sample, sayHi} from "./module1.js" 
  3. import Sample, * as M1 from "./module1.js" 

 

當然,也可以將整個模塊作為副作用而導入,而不導入模塊中的特定內容。這將運行模塊中的全局代碼,但實際上不導入任何值。

 

  1. import './module1.js' 

import 導入的值與 export 導出的值是綁定關系,綁定是不可變的。因此,import 對所導入的模塊是只讀的。但是可以通過調用被導入模塊的函數來達到目的。

 

  1. import Sample, * as M1 from "./module1.js" 
  2. Sample = "Modify Sample";    // 錯誤 
  3. M1.module1 = "Module 1";    // 錯誤 
  4. Sample.name = "小亮";       // 允許 

 

這樣做的好處是能夠支持循環依賴,并且一個大的模塊可以拆成若干個小模塊時也可以運行,只要不嘗試修改導入的值。

注意:如果要在瀏覽器中原生加載模塊,則文件必須帶有 .js 擴展名,不然可能無法解析。而使用構建工具或第三方模塊加載器打包或解析 ES6 模塊,可能不需要包含擴展名。

import()

標準的 import 關鍵字導入模塊是靜態的,會使所有被導入的模塊,在加載時就被編譯。而最新的 ES11 標準中引入了動態導入函數 import(),不必預先加載所有模塊。該函數會將模塊的路徑作為參數,并返回一個 Promise,在它的 then 回調里使用加載后的模塊:

 

  1. import ('./module1.mjs'
  2.     .then((module) => { 
  3.         // Do something with the module. 
  4.     }); 

 

這種使用方式也支持 await 關鍵字。

 

  1. let module = await import('./module1.js'); 

import() 的使用場景如下:

  • 按需加載。
  • 動態構建模塊路徑。
  • 條件加載。

加載

ES6 模塊既可以通過瀏覽器原生加載,也可以與第三方加載器和構建工具一起加載。

完全支持 ES6 模塊的瀏覽器可以從頂級模塊異步加載整個依賴圖。瀏覽器會解析入口模塊,確定依賴,并發送對依賴模塊的請求。這些文件通過網絡返回后,瀏覽器會解析它們的內容,確認依賴,如果二級依賴還沒有加載,則會發送更多請求。這個異步遞歸加載過程會持續到整個依賴圖都解析完成。解析完依賴,應用就可以正式加載模塊了。

模塊文件按需加載,且后續模塊的請求會因為每個依賴模塊的網絡延遲而同步延遲。即,module1 依賴 module2,module2 依賴 module3。瀏覽器在對 module2 的請求完成之前并不知道要請求 module3。這種架子啊方式效率高,也不需要外部工具,但加載大型應用的深度依賴圖可能要花費很長時間。

HTML

想要在 HTML 頁面中使用 ES6 模塊,需要將 type="module" 屬性放在 <script> 標簽中,來聲明該 <script> 所包含的代碼在瀏覽器中作為模塊執行。它可以嵌入在網頁中,也可以作為外部文件引入:

 

  1. <script type="module"
  2.     // 模塊代碼 
  3. </script> 
  4. <script type="module" src="./module1.js"></script> 

 

 

<script type="module">模塊加載的順序與 <script defer> 加載的腳本一樣按順序執行。但執行會延遲到文檔解析完成,但執行順序就是<script type="module">在頁面中出現的順序。

也可以給模塊標簽添加 async 屬性。這樣影響是雙重的,不僅模塊執行順序不再與 <script> 標簽在頁面中的順序綁定,模塊也不會等待文檔完成解析才執行。不過,入口模塊必須等待其依賴加載完成。

Worker

 

Worker 為了支持 ES6 模塊,在 Worker 構造函數中可以接收第二個參數,其 type 屬性的默認值是 classic,可以將 type 設置為 module 來加載模塊文件。如下所示:

  1. // 第二個參數默認為{ type: 'classic' } 
  2. const scriptWorker = new Worker('scriptWorker.js'); 
  3. const moduleWorker = new Worker('moduleWorker.js', { type: 'module' }); 

在基于模塊的工作者內部,self.importScripts() 方法通常用于在基于腳本的工作者中加載外部腳本,調用它會拋出錯誤。這是因為模塊的 import 行為包含了 importScripts()。

向后兼容

如果瀏覽器原生支持 ES6 模塊,可以直接使用,而不支持的瀏覽器可以使用第三方模塊系統(System.js)或在構建時將 ES6 模塊進行轉譯。

 

腳本模塊可以使用 type="module" 屬性設定,而對于不支持模塊的瀏覽器,可以使用 nomodule 屬性。此屬性會通知支持 ES6 模塊的瀏覽器不執行腳本。不支持模塊的瀏覽器無法識別該屬性,從而忽略該屬性。如下所示:

  1. // 支持模塊的瀏覽器會執行這段腳本 
  2. // 不支持模塊的瀏覽器不會執行這段腳本 
  3. <script type="module" src="module.js"></script> 
  4. // 支持模塊的瀏覽器不會執行這段腳本 
  5. // 不支持模塊的瀏覽器會執行這段腳本 
  6. <script nomodule src="script.js"></script> 

總結

ES6 在語言層面上支持了模塊,結束了 CommonJS 和 AMD 這兩個模塊加載器的長期分裂狀況,重新定義了模塊功能,集兩個規范于一身,并通過簡單的語法聲明來暴露。

模塊的使用不同方式加載 .js 文件,它與腳本有很大的不同:

  1. 模塊始終使用 use strict 執行嚴格模式。
  2. 在模塊的頂級作用域創建的變量,不會被自動添加到共享的全局作用域,它們只會在模塊頂級作用域的內部存在。
  3. 模塊頂級作用域的 this 值為 undefined。
  4. 模塊不允許在代碼中使用 HTML 風格的注釋。
  5. 對于需要讓模塊外部代碼訪問的內容,模塊必須導出它們。
  6. 允許模塊從其他模塊導入綁定。
  7. 模塊代碼執行一次。導出僅創建一次,然后會在導入之間共享。

 

瀏覽器對原生模塊的支持越來越好,但也提供了穩健的工具以實現從不支持到支持 ES6 模塊的過渡。

 

責任編輯:華軒 來源: 今日頭條
相關推薦

2020-07-09 08:01:48

JavaScriptES模塊

2015-08-26 16:17:49

OpenStack OpenStack 架開源云平臺

2012-07-25 13:25:11

ibmdw

2016-12-30 13:43:35

異步編程RxJava

2009-11-17 09:47:54

Oracle SQL語

2009-11-13 15:55:52

Oracle哈希連接

2023-11-06 09:24:14

CSS相對顏色

2022-08-04 18:50:12

Navigator瀏覽器設備

2019-11-06 09:52:01

JavaScript單線程非阻塞

2017-01-20 08:30:19

JavaScriptfor循環

2012-02-06 13:52:33

JavaScript

2011-05-25 11:25:23

快速排序Javascript

2019-12-02 16:05:10

前端模塊化JavaScript

2010-01-12 10:23:52

路由最佳路徑

2024-01-09 07:42:46

Shutil 模塊Python 編程工具

2009-11-12 10:05:09

Visual C++

2010-09-13 09:18:22

JavaScript模塊模式

2020-12-25 10:28:41

JavaScript模塊module

2013-11-06 11:03:26

2017-10-26 08:53:38

前端JavaScript函數式編程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品久久电影 | 日韩欧美1区2区 | 欧美亚洲一级 | 一区二区三区国产精品 | 日韩中文字幕一区 | 成人性生交大片免费看中文带字幕 | 国产精品美女久久久av超清 | 欧美一区二区三区在线观看 | 天天爽夜夜爽精品视频婷婷 | 久久亚洲国产 | 我想看一级黄色毛片 | 亚洲a在线观看 | 我要看一级片 | 精品视频在线免费观看 | 亚洲一二三区在线观看 | av一区二区三区 | 国产午夜精品久久久久免费视高清 | 精品国产乱码久久久久久丨区2区 | 国产精品毛片 | 在线日韩视频 | 午夜www| 欧美日韩午夜精品 | 欧美一区永久视频免费观看 | 免费在线观看av | 国产精品夜夜春夜夜爽久久电影 | 日韩欧美大片在线观看 | 久久久男人的天堂 | 久久久久久久综合色一本 | 毛片av免费看 | 黄网免费看| 欧美一区免费在线观看 | 午夜影院中文字幕 | 国产精品免费大片 | 91亚洲精品在线 | 欧美一区二区三区在线观看视频 | 精品久久久久久久久久久院品网 | 国产亚洲第一页 | 97caoporn国产免费人人 | 成人免费视频网站在线看 | 天色综合网 | 天天干人人 |