js模塊化發展史與commonJs,ES6模塊化規範介紹

JavaScript 模塊化發展史

第一階段

在 JavaScript 語言剛剛誕生,js只用於實現小的效果,js代碼通常只有幾百行,專業的前端工程師還沒有出現,都是後端順帶完成前端工作
大事件

  • 1996年,NetScape將JavaScript語言提交給歐洲的一個標準制定阻止ECMA(歐洲計算機制造商協會)

  • 1998年,NetScape在與微軟瀏覽器IE的競爭中失利,宣佈破產

第二階段

隨着ajax的出現,改變了 JavaScript 在瀏覽器中扮演的角色,js可以與服務器進行交互,優化了用戶體驗。
js代碼逐漸增加,前端邏輯逐漸複雜。
但是前端規模沒有進一步擴大,主要由於以下幾個原因

  • 瀏覽器解釋執行JS的速度太慢
  • 用戶端的電腦配置不足
  • 更多的代碼帶來了全局變量污染、依賴關係混亂等問題
    大事件
  • IE瀏覽器制霸市場後,幾乎不再更新
  • ES4.0流產,導致JS語言10年間幾乎毫無變化
  • 2008年ES5發佈,僅解決了一些 JS API 不足的糟糕局面

第三階段

到了2008年,谷歌的 V8 引擎發佈,將JS的執行速度推上了一個新的臺階,甚至可以和後端語言媲美。
摩爾定律持續發酵,個人電腦的配置開始飛躍(摩爾定律指的是當價格不變時,集成電路上可容納的元器件的數目,約每隔18-24個月便會增加一倍,性能也將提升一倍。)
同時,nodejs誕生,對模塊化的需求進一步加深,

經過社區的激烈討論,最終,形成了一個模塊化方案,即鼎鼎大名的CommonJS,該方案,徹底解決了全局變量污染和依賴混亂的問題

該方案一出,立即被nodejs支持,於是,nodejs成爲了第一個爲JS語言實現模塊化的平臺,爲前端接下來的迅猛發展奠定了實踐基礎
大事件

  • 2008年,V8發佈
  • IE的市場逐步被 firefox 和 chrome 蠶食,現已無力迴天
  • 2009年,nodejs發佈,並附帶commonjs模塊化標準

第四階段

隨着後端模塊化的誕生,前段模塊化也相繼出現AMD,CMD,終於在2015年,ES6發佈,它提出了官方的模塊化解決方案 —— ES6 模塊化
前端模塊化的出現使得一些框架相繼誕生

既然JS也能編寫大型應用,那麼自然也需要像其他語言那樣有解決複雜問題的開發框架

  • Angular、React、Vue等前端開發框架出現
  • Express、Koa等後端開發框架出現
  • 各種後端數據庫驅動出現

要開發大型應用,自然少不了各種實用的第三方庫的支持

  • npm包管理器出現,實用第三方庫變得極其方便
  • webpack等構建工具出現,專門用於打包和部署

總結

由於ajax的出現,js代碼量激增,同時也完成了更多的任務,但是由於代碼量的增多,js暴露出來三個問題(1.js執行速度太慢2.用戶電腦配置不高3.代碼增多導致全局變量污染),v8引擎的出現與摩爾定律的發酵,解決了前兩個問題,nodejs和commonJs的出現,也將前端模塊化推上日程,於是出現了三種前端模塊化解決方案(AMD,CMD,ES6),前端模塊化的出現也給框架的誕生提供了基礎

模塊化規範介紹

由於nodejs剛剛發佈的時候,前端沒有統一的、官方的模塊化規範,因此,它選擇使用社區提供的CommonJS作爲模塊化規範

在學習CommonJS之前,首先認識兩個重要的概念:模塊的導出和模塊的導入

何爲導出

要理解模塊的導出,首先要理解模塊的含義

什麼是模塊?

模塊就是一個JS文件,它實現了一部分功能,並隱藏自己的內部實現,同時提供了一些接口供其他模塊使用

模塊有兩個核心要素:隱藏和暴露

     隱藏的,是自己內部的實現
     暴露的,是希望外部使用的接口

任何一個正常的模塊化標準,都應該默認隱藏模塊中的所有實現,而通過一些語法或api調用來暴露接口

何爲導入

當需要使用一個模塊時,使用的是該模塊暴露的部分(導出的部分),隱藏的部分是永遠無法使用的。

當通過某種語法或api去使用一個模塊時,這個過程叫做模塊的導入

nodejs對CommonJS的實現

爲了實現CommonJS規範,nodejs對模塊做出了以下處理

  1. 爲了保證高效的執行,僅加載必要的模塊。nodejs只有執行到require函數時纔會加載並執行模塊(這叫做依賴延遲聲明)

  2. 爲了隱藏模塊中的代碼,nodejs執行模塊時,會將模塊中的所有代碼放置到一個函數中執行,以保證不污染全局變量。

     (function(){
         //模塊中的代碼
     })()
    
  3. 爲了保證順利的導出模塊內容,nodejs做了以下處理

    1. 在模塊開始執行前,初始化一個值module.exports = {}
    2. module.exports即模塊的導出值
    3. 爲了方便開發者便捷的導出,nodejs在初始化完module.exports後,又聲明瞭一個變量exports = module.exports
     (function(module){
         module.exports = {};
         var exports = module.exports;
         //模塊中的代碼
         return module.exports;
     })()
    
  4. 爲了避免反覆加載同一個模塊,nodejs默認開啓了模塊緩存,如果加載的模塊已經被加載過了,則會自動使用之前的導出結果

commonJs的導出

module.export.xxx = xxx;
module.export.xxx = {
	xxx: xxx
}

commonJs的導入

var xxx = require('./xxx.js'); // 路徑必須爲相對路徑

es6的官方模塊化標準

es6模塊化標準通過script標籤來引入文件,使用type="module"來聲明此文件作爲一個模塊來執行

es6模塊化特點如下

  1. 使用依賴依賴預聲明的方式導入模塊
  2. 靈活的多種導入導出方式
  3. 規範的路徑表示法:所有路徑必須以./或…/開頭

es6模塊化的基本導入導出
導出
es6的基本導出可以有多個,每個都必須是聲明表達式,或具名符號

export const a = 1;
export const b = 2;
// 這樣是不可以的↓
const c = 3;
export c;

es6的模塊化支持簡寫

const a = 1;
const b = 2;
const c = 3;
export {a, b, c}; 
// 導出時支持重命名
export {a as a1, b as b2, c as c3}; 

導入

import {a, b} from './xxx.js'; // 只需要導入需要的變量,c不需要就可以不導入
// 同樣的導入時也支持重命名導入數據
import {a as a1, b as b2} from './xxx.js';

es6模塊化的默認導入導出

導出

export default 默認導出的數據

或者

export {默認導出的數據 as default}

由於每個模塊僅允許有一個默認導出,因此,每個模塊不能出現多個默認導出語句

導入

import xxx from './xxx.js'; // 由於默認導出沒有給數據命名,所以不存在重命名

導入導出混合寫法

一個模塊裏可以同時存在基本導入導出與默認導入導出
導出

const a = 1;
const b = 2;
const c = 3;
export {a, b, c};
export default {d: 4}

導入

import d, {a, b, c} from './xxx.js';
// d爲默認導出,abc爲正常導出

import * as data from './xxx.js';
// data中有一個屬性叫做default,這個屬性值即爲默認導出數據
// 想導入所有正常導出,也可以使用*

es6模塊化的其他細節

  1. 儘量導出不可變值

儘量使用const定義導出的數據,確保它在本模塊內也是一個常量。
因爲,雖然導入後,無法更改導入內容,但是在導入的模塊內部卻有可能發生更改,這將導致一些無法預料的事情發生

  1. 可以使用無綁定的導入用於執行一些初始化代碼

如果我們只是想執行模塊中的一些代碼,而不需要導入它的任何內容,可以使用無綁定的導入:

import "模塊路徑"
  1. 可以使用綁定再導出,來重新導出來自另一個模塊的內容

有的時候,我們可能需要用一個模塊封裝多個模塊,然後有選擇的將多個模塊的內容分別導出,可以使用下面的語法輕鬆完成

export {綁定的標識符} from "模塊路徑"

例如a.js需要依賴b.js,b.js需要依賴c.js。
b.js需要原封不動的導出c.js裏的變量c。
那麼,b.js可以這樣寫

export { c } from './c.js';
 

依賴延遲聲明與依賴預聲明的區別

  1. 依賴延遲聲明
    1. 優點:某些時候可以提高效率(某些情況見下方例子)
    2. 缺點:無法在一開始確定模塊依賴關係(比較模糊)
  2. 依賴預聲明
    1. 優點:在一開始可以確定模塊依賴關係
    2. 缺點:某些時候效率較低

nodejs執行在本地,文件從本地讀取,速度快,所以commonJs使用依賴延遲聲明
而瀏覽器讀取文件需要請求,速度較慢,使用依賴預聲明
es6模塊化標準的導入,應該寫在js最上面,即使不寫在最上面,瀏覽器在預編譯的時候,也會將導入模塊置於頂部

if (Math.random() > 0.5) {
	// 導入A模塊
} else {
	// 導入B模塊
}

當這種情況出現的時候,依賴延遲聲明效率較高

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章