JS模組化規範

weixin_34148340發表於2018-12-24

模組化規範

伺服器端規範主要是CommonJS,node.js用的就是CommonJS規範。
客戶端規範主要有:AMD、CMD。 AMD規範的實現主要有RequireJS,CMD規範的主要實現有SeaJS。RequireJS在國外用的比較多,SeaJS在國內用的比較多,並且SeaJS的創始人為阿里的玉伯。


6897582-e7dfd92d6c06e7f0.png
模組化圖解.png

區別

CMD 推崇依賴就近;AMD 推崇依賴前置
CMD 是延遲執行;AMD 是提前執行
CMD效能好,因為只有使用者需要的時候才執行;AMD使用者體驗好,因為沒有延遲,依賴模組提前執行了

ES6模組

1:每一個模組只載入一次, 每一個JS只執行一次, 如果下次再去載入同目錄下同檔案,直接從記憶體中讀取。 一個模組就是一個單例,或者說就是一個物件;
2:每一個模組內宣告的變數都是區域性變數, 不會汙染全域性作用域;
3:模組內部的變數或者函式可以通過export匯出;
4:一個模組可以匯入別的模組

語法

export

//模組功能主要由兩個命令構成:export和import。export命令用於規定模組的對外介面,import命令用於輸入其他模組提供的功能
**特別注意**
// 報錯
export 1;
// 報錯
var m = 1;
export m;

**正確寫法**
// 寫法一
export var m = 1;
// 寫法二
var m = 1;
export {m};
// 寫法三
var n = 1;
export {n as m};

//同樣的,function和class的輸出,也必須遵守這樣的寫法。
// 報錯
function f() {}
export f;

// 正確
export function f() {};
// 正確
function f() {}
export {f};
// 正確
function f() {}
export {f as m};

通常情況下,export輸出的變數就是本來的名字,但是可以使用as關鍵字重新命名。

function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};
//上面程式碼使用as關鍵字,重新命名了函式v1和v2的對外介面。重新命名後,v2可以用不同的名字輸出兩次。

import

import {firstName, lastName, year} from './profile.js';

//如果想為輸入的變數重新取一個名字,import命令要使用as關鍵字,將輸入的變數重新命名。
import { lastName as surname } from './profile.js';

示例:
模組的單一載入

//a.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {
    firstName, 
    lastName, 
    year
};
//b.js
import {firstName,lastName} from './js/my.js';
console.log(firstName);//Michael
console.log(lastName);//Jackson
console.log(year);//1958

輸出部分如果使用export {},可以為每個輸出項設定as重新命名,引用部分import 需要使用{},也可以使用as重新命名

模組的整體載入

function area(radius) {
  return Math.PI * radius * radius;
}
function circumference(radius) {
  return 2 * Math.PI * radius;
}
export {
    area,
    circumference
}

import * as circle from './circle';
console.log('圓面積:' + circle.area(4));
console.log('圓周長:' + circle.circumference(14));
引用部分import 如果使用整體載入,輸出部分export{}則不可以使用as重新命名
//a.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export default {
    firstName, 
    lastName, 
    year
};
//b.js
import data from './js/my.js';
console.log(data);// {firstName: "Michael", lastName: "Jackson", year: 1958}
console.log(data.firstName);//Michael
console.log(data.lastName);//Jackson
console.log(data.year);//1958

輸出部分如果使用export default {},為全部輸出,不可以重新命名,引用部分import 需要去掉{},
推薦使用此寫法:
好處:
1.不會因為誤操作將一些無關變數匯出 
2.通過 export default,由第三方引用時無需知道其名稱,較為簡潔

因為export default命令其實只是輸出一個叫做default的變數,所以它後面不能跟變數宣告語句。

// 正確
export var a = 1;
// 正確
var a = 1;
export default a;
// 錯誤
export default var a = 1;

動態載入 import()
import函式的引數specifier,指定所要載入的模組的位置。import命令能夠接受什麼引數,import()函式就能接受什麼引數,兩者區別主要是後者為動態載入
(1)按需載入

button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
    dialogBox.open();
  })
  .catch(error => {
    /* Error handling */
  })
});

(2)條件載入

if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}

(3)動態的模組路徑

import(f())
.then(...);

如果模組有default輸出介面,可以用引數直接獲得

import('./myModule.js')
.then(myModule => {
  console.log(myModule.default);
});
//上面的程式碼也可以使用具名輸入的形式
import('./myModule.js')
.then(({default: theDefault}) => {
  console.log(theDefault);
});

如果想同時載入多個模組,可以採用下面的寫法

Promise.all([
  import('./module1.js'),
  import('./module2.js'),
  import('./module3.js'),
])
.then(([module1, module2, module3]) => {
   ···
});

import()也可以用在 async 函式之中

async function main() {
  const myModule = await import('./myModule.js');
  const {export1, export2} = await import('./myModule.js');
  const [module1, module2, module3] =
    await Promise.all([
      import('./module1.js'),
      import('./module2.js'),
      import('./module3.js'),
    ]);
}
main();

相關文章