[toc]
### ES6模塊化簡介
ECMA組織參考了眾多社區模塊化標準,終于在2015年,隨著ES6發布了官方的模塊化標準,后成為ES6模塊化
ES6模塊化具有以下的特點
1. 使用依賴**預聲明**的方式導入模塊
1. 依賴延遲聲明(CommonJS采用的模塊加載方式)
1. 優點:某些時候可以提高效率
2. 缺點:無法在一開始確定模塊依賴關系(比較模糊)
2. 依賴預聲明(ES6采用的模塊加載方式)
1. 優點:在一開始可以確定模塊依賴關系
2. 缺點:某些時候效率較低
2. 靈活的多種導入導出方式
3. 規范的路徑表示法:所有路徑必須以./或../開頭
### 基本導入導出
#### 模塊的引入
**注意:這一部分非模塊化標準**
目前,瀏覽器使用以下方式引入一個ES6模塊文件
```html
<script src="入口文件" type="module">
//不加type="module"為正常引入js文件,文件中用var定義的變量會污染全局變量
//加了type="module"為引入一個模塊文件,文件中定義的變量不會污染全局變量
```
#### 模塊的基本導出和導入
ES6中的模塊導入導出分為兩種:
1. 基本導入導出
2. 默認導入導出

#### 基本導出
類似于CommonJS的 ``` exports.xxx = xxxx ```
基本導出可以有多個,每個必須有名稱
基本導出的語法如下:
```js
export 聲明表達式
//聲明表達式必須是新聲明的具有聲明標識符的語句,如帶有var、let、const、function函數名(){}、class類名的語句
```
```js
export var a = 5; //正確的導出方式。表示導出a,其值為5
//下面三種導出方式均是錯誤的導出方式
var a = 1;
export a;
export a = 5;
export 5;
```
或
```js
export {具名符號}
```
```js
//當已經聲明了一個變量,導出時又不想改變變量的名稱時,即可以使用該方法導出。
let name = 'xiaoming'; //定義了一個變量name
let age = 20; //定義了一個變量age
export { name, age }; //大括號為導出的一種格式,并不是表示導出一個對象。這條語句表示導出兩個變量,name和age,將name變量名稱做為導出名稱,name的值做為導出的值。
```
由于基本導出必須具有名稱,所以要求導出內容必須跟上**聲明表達式**或**具名符號**
#### 基本導入
由于使用的是**依賴預加載**,因此,導入任何其他模塊,導入代碼必須放置到所有代碼之前
對于基本導出,如果要進行導入,使用下面的代碼
```js
import {導入的符號列表} from "模塊路徑"
```
```js
import { name, age } from "./module.js"; //正常導入name和age兩個變量
```
```js
//如果文件中已經定義了name,可以使用as關鍵字修改導入的變量名
import{ name as name1, age} from "./module.js";
var name = "xiaozhang";
console.log(name, name1); //輸出xiaozhang xiaoming
```
```js
//若想導入模塊中的所有變量,可以使用*號導入,且必須用as重命名。其會將該導入包裝成一個以as重命名為名的對象
import * as person from "./module.js";
console.log(person.name); //輸出xiaoming
```
注意以下細節:
- import語句須在文件的最上方書寫,多個文件導入寫多行import即可。不能在函數體或條件語句中導入。
- 導入時,可以通過關鍵字```as```對導入的符號進行重命名
- 導入時使用的符號是常量,不可修改
- 可以使用*號導入所有的基本導出,形成一個對象
```js
import "./module.js";
//如果只想執行一下模塊中的代碼,并不使用模塊中導出的任何功能,或模塊中本就沒有導出任何變量,可以使用上面的語句。即表示執行了一次module.js中的代碼。但因為ES6中模塊加載有緩存機制,所以同一個模塊只有在第一次加載的時候才會執行。這種方式適用于程序的初始化模塊,僅在運行程序的時候執行一次,并不需要導出什么功能。
```
### 默認導入導出

#### 默認導出
每個模塊,除了允許有多個基本導出之外,還允許有一個默認導出。
默認導出和基本導出可以同時存在。
默認導出類似于CommonJS中的```module.exports```,由于只有一個,因此無需具名
具體的語法是
```js
export default 默認導出的數據
```
或
```js
export {默認導出的數據 as default}
```
由于每個模塊僅允許有一個默認導出,因此,每個模塊不能出現多個默認導出語句
#### 默認導入
需要想要導入一個模塊的默認導出,需要使用下面的語法
```js
import 接收變量名 from "模塊路徑"
```
類似于CommonJS中的
```js
var 接收變量名 = require("模塊路徑")
```
由于默認導入時變量名是自行定義的,因此沒有別名一說
如果希望同時導入某個模塊的默認導出和基本導出,可以使用下面的語法
```js
import 接收默認導出的變量, {接收基本導出的變量} from "模塊路徑"
```
注:如果使用*號,會將所有基本導出和默認導出聚合到一個對象中,默認導出會作為屬性default存在
### ES6模塊化的其他細節
1. **盡量導出不可變值**
當導出一個內容時,盡量保證該內容是不可變的(大部分情況都是如此)
因為,雖然導入后,無法更改導入內容,但是在導入的模塊內部卻有可能發生更改,這將導致一些無法預料的事情發生
2. **可以使用無綁定的導入用于執行一些初始化代碼**
如果我們只是想執行模塊中的一些代碼,而不需要導入它的任何內容,可以使用無綁定的導入:
```js
import "模塊路徑"
```
3. **可以使用綁定再導出,來重新導出來自另一個模塊的內容**
有的時候,我們可能需要用一個模塊封裝多個模塊,然后有選擇的將多個模塊的內容分別導出,可以使用下面的語法輕松完成
```js
export {綁定的標識符} from "模塊路徑"
```
