知識點【JavaScript模塊化】

JavaScript模塊化歷程

JavaScript發展變遷大概是一下幾個步驟:javascript

  • 工具(瀏覽器兼容)vue

  • 組件(功能模塊)java

  • 框架(功能模塊組織)node

  • 應用(業務模塊組織)es6

可是通過了長長的後天努力過程JavaScript不斷被類聚抽象,以更好的組織業務邏輯。從另外一個角度而言,他也道出了JavaScript先天就缺少的一項功能:模塊數據庫

雖然W3C組織對HTML5規範推動以及各大廠對規範的大力支持,可是對於JavaScript自己而言,它的規範依然是薄弱的,它還有如下缺陷:瀏覽器

  • 沒有標準模塊系統緩存

  • 標準庫少(ECMAScript僅定義了部分核心庫)服務器

  • 沒有標準接口(JavaScript幾乎沒有定義過如WEB服務器數據庫操做之類的標準統一接口)app

  • 缺少包管理系統

CommonJS規範

CommonJS規範的提出,主要爲了彌補JavaScript沒有標準的缺陷,以達到想Python、Ruby和Java具有開發大型應用的基礎能力,而不是停留在小腳本程序的階段。

它的使用和定義也很是簡單

CommonJS的模塊規範

1 模塊定義

// example.js
var x =5;
var addx = function (value){
    return value + x;
}
module.exports.x = x;
module.exports.addx = addx;

 定義關鍵字是exports這個module是什麼意思呢:在CommonJS定義了每一個文件都一個模塊,也就是說module表明文件自己

2 模塊引用

var example = require('./example.js');

console.log(example.x);  // 5
console.log(example.addx(1)); // 6

CommonJS模塊特色以下:

  • 全部代碼都運行在模塊做用域,不會污染全局做用域。

  • 模塊能夠屢次加載,可是隻會在第一次加載時運行一次,而後運行結果就被緩存了,之後再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。

  • 模塊加載的順序,按照其在代碼中出現的順序。

3 看圖

用一個圖很明顯的看出它們之間的引用關係

 

模塊的實現

在Node中引入模塊,須要經歷3個步驟

一、路徑分析

二、文件定位

三、編譯執行

 

在Node中模塊分爲兩類:一類是Node提供的模塊,稱爲核心模塊;另外一類是用戶編寫的模塊稱爲文件模塊

ES6 Module

ES6 模塊的設計思想,是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時肯定這些東西。好比,CommonJS 模塊就是對象,輸入時必須查找對象屬性。

// CommonJS模塊
let { stat, exists, readFile } = require('fs');

// 等同於
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

上面代碼的實質是總體加載fs模塊(即加載fs的全部方法),生成一個對象(_fs),而後再從這個對象上面讀取3個方法。這種加載稱爲「運行時加載」,由於只有運行時才能獲得這個對象,致使徹底沒辦法在編譯時作「靜態優化」。

ES6 模塊不是對象,而是經過export命令顯式指定輸出的代碼,再經過import命令輸入。

 

與CommonJS思想相似

1 模塊定義

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

上面代碼是profile.js文件,保存了用戶信息。ES6 將其視爲一個模塊,裏面用export命令對外部輸出了三個變量。

export的寫法,除了像上面這樣,還有另一種。

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

一般狀況下,export輸出的變量就是原本的名字,可是可使用as關鍵字重命名。

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

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

注意規範:

export命令規定的是對外的接口,必須與模塊內部的變量創建一一對應關係。

// 報錯
export 1;

// 報錯
var m = 1;
export m;

上面兩種寫法都會報錯,由於沒有提供對外的接口。第一種寫法直接輸出1,第二種寫法經過變量m,仍是直接輸出1。1只是一個值,不是接口。正確的寫法是下面這樣。

// 寫法一
export var m = 1;

// 寫法二
var m = 1;
export {m};

// 寫法三
var n = 1;
export {n as m};

functionclass的輸出,也必須遵照這樣的寫法。

// 報錯
function f() {}
export f;

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

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

另外,export語句輸出的接口,與其對應的值是動態綁定關係,即經過該接口,能夠取到模塊內部實時的值。

2 模塊引用

// a.js
let a = 18;
let funcA = function () {
    console.log('module A')
};

// 提供一個對外的藉口並輸出a變量和funcA方法
export {a, funcA}

引用

import {a, funcA} from "./a";

// 經過import 引入裏面的變量和方法
console.log(a);
console.log(funcA());

引用的時候能夠設置別名

import {a as aValue, funcA} from "./a";

// 經過import 引入裏面的變量和方法
console.log(aValue);
console.log(funcA());

3 export default命令

從前面的例子能夠看出,使用import命令的時候,用戶須要知道所要加載的變量名或函數名,不然沒法加載。可是,用戶確定但願快速上手,未必願意閱讀文檔,去了解模塊有哪些屬性和方法。

爲了給用戶提供方便,讓他們不用閱讀文檔就能加載模塊,就要用到export default命令,爲模塊指定默認輸出

本質上,export default就是輸出一個叫作default的變量或方法,而後系統容許你爲它取任意名字

// export-default.js
export default function () {
  console.log('foo');
}

而後你能夠隨便命名

// import-default.js
import customName from './export-default';
customName(); // 'foo'

可是正常引入模塊的狀況下你必須指定你要引入的變量或者方法,像下面同樣:

import {funcA} from "./a.js";  // 這裏你在引用的時候你必須知道a.js中定義的方法的名字

比較下正常和export default不一樣

// 第一組
export default function crc32() { // 輸出
  // ...
}

import crc32 from 'crc32'; // 輸入

// 第二組
export function crc32() { // 輸出
  // ...
};

import {crc32} from 'crc32'; // 輸入

Module 的加載實現

上面是模塊的語法,接下來看看如何在瀏覽器和Node中加載ES6模塊

瀏覽器加載ES6模塊

在 HTML 網頁中,瀏覽器經過<script>標籤加載 JavaScript 腳本

<!-- 頁面內嵌的腳本 -->
<script type="application/javascript">
  // module code
</script>

<!-- 外部腳本 -->
<script type="application/javascript" src="path/to/myModule.js">
</script>

上面代碼中,因爲瀏覽器腳本的默認語言是 JavaScript,所以type="application/javascript"能夠省略。

一樣若是你的目錄結構是這樣的:

你在本地安裝了node_js模塊vue的話一樣能夠直接經過script標籤引用

瀏覽器加載ES6模塊

瀏覽器加載 ES6 模塊,也使用<script>標籤,可是要加入type="module"屬性。

<script type="module" src="./foo.js"></script>

瀏覽器對於帶有type="module"<script>,都是異步加載,不會形成堵塞瀏覽器,即等到整個頁面渲染完,再執行模塊腳本,等同於打開了<script>標籤的defer屬性。

<script type="module" src="./foo.js"></script>
<!-- 等同於 -->
<script type="module" src="./foo.js" defer></script>

ES6 模塊也容許內嵌在網頁中,語法行爲與加載外部腳本徹底一致。

<script type="module">
  import utils from "./utils.js";

  // other code
</script>

 

 

參考資料:http://es6.ruanyifeng.com/#docs/module

相關文章
相關標籤/搜索