騷年,你對前端模塊化了解多少

前言

不論是前端老司機仍是剛接觸前端的"菜鳥"。模塊化想必在天天工做中,或多或少都會接觸到。尤爲針對一些針對ReactVue開發的同窗來講,那就是天天都會脫口而出的一個必備術語。而且在不少技術文檔中,都經常看到AMDUMDCOMMONJS還有ES6中的modulejavascript

可是,模塊化的本質是什麼!前端是如何從"茹毛飲血"的<script>到如今es6的module的呢。html

今天咱們就來嘮嘮這段不爲人知的故事。前端

模塊化本質

何爲模塊化。其實就是功能的單一化或者說功能的切片化編程。更直白一點就是,每個獨立的功能都有本身獨立的做用域java

讓咱們看看針對模塊的英文定義es6

Modules are an integral piece of any robust application's architecture and typically help in keeping the units of code for a project both cleanly separated and organized.編程

而JS在實現模塊代碼有以下方式:設計模式

  1. 對象字面量
  2. 設計模式中的模塊模式
  3. AMD
  4. CommonJS
  5. ES6 module

讓咱們針對每個方式來一一說明api

對象字面量

因爲JS語法自己沒有塊級做用域的概念(es6以前),因此是無法直接利用{}來將指定的代碼進行封裝。若是想將特定用於處理相似功能的代碼合併到一塊兒。對象字面量不失爲一個很好的方式。(有人會說,用函數封裝也能夠啊,記住JS中一切皆對象)瀏覽器

Talk is cheap ,show you the code

var myModule = {
 
  myProperty: "北宸",
 
  // 對象字面量能夠包含屬性和方法
  // 咱們還能夠爲該模塊定義配置信息:
  myConfig: {
    useCaching: true,
    language: "en"
  },
 
  // 
  saySomething: function () {
    console.log( "你好啊,世界" );
  },
 
  // 基於配置信息輸出一些信息
  reportMyConfig: function () {
    console.log( "緩存: " + ( this.myConfig.useCaching ? "可用" : "禁用") );
  },
 
  // 從新配置信息
  updateMyConfig: function( newConfig ) {
 
    if ( typeof newConfig === "object" ) {
      this.myConfig = newConfig;
      console.log( this.myConfig.language );
    }
  }
};
 
// 你好啊,世界
myModule.saySomething();
 
// 緩存可用
myModule.reportMyConfig();
 
// fr
myModule.updateMyConfig({
  language: "fr",
  useCaching: false
});
 
// 緩存禁用
myModule.reportMyConfig();

複製代碼

從上述代碼中,能夠看到,將一些操做和數據進行了封裝。實現了,功能切片化處理。可是若是細想,感受利用字面量來封裝數據和方法,感受有點雞肋。由於這個對象是一個單例。若是隻是在一個地方使用和操做,那徹底沒有問題,可是若是是多個地方都用到呢,同時多個地方都須要對指定的屬性進行修改。這就是牽一髮而動全身的操做。緩存

同時,咱們能夠看到利用字面量進行數據和方法封裝。這些屬性都是對外友好的。都是能在外部訪問到的。沒有絲毫的隱私,用傳統OOP編程術語來說。這些屬性都是public的。也就是說,沒法實現屬性私有化

模塊模式

爲了解決字面量沒法進行屬性私有化。模塊模式應用而生。這也是JS語言在早起比較經常使用的模塊化處理方式。

Talk is cheap ,show you the code

var MODULE = (function () {
	var my = {},
		privateVariable = 1;

	function privateMethod() {
		// ...
	}

	my.moduleProperty = 1;
	my.moduleMethod = function () {
		// ...
	};

	return my;
}());
複製代碼

從代碼上看到,一個IIFE赫然映入眼簾。偷偷的告訴你們,模塊模式就是利用IIFE實現的。

爲了避免佔用很大篇幅來說解這個實現。特定爲你們準備了飯後甜點。JS_Module模式深刻了解一下

AMD

其實AMD(Asynchronous Module Definition)是一種爲瀏覽器環境書寫模塊的模式。 而可以實現異步加載的關鍵就在於RequireJS

RequireJS是在ES6module沒出現以前,經常使用的前端模塊解決方案。RequireJS將加載的每個獨立模塊做爲<script>,並利用head.appendChild()追加到文檔中。

RequireJS等待全部依賴模塊加載,將該模塊須要的額外模塊進行排序,並在依賴模塊加載完以後,調用本模塊的定義函數。

Talk is cheap,show you the code

在項目中存在以下結構,咱們用cart.jsinventory.js來構建一個shirt.js

  • my/cart.js
  • my/inventory.js
  • my/shirt.js
define(["./cart", "./inventory"], function(cart, inventory) {
        //返回一個對象用於定義"my/shirt"模塊
        return {
            color: "blue",
            size: "large",
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
);

複製代碼

固然,上述中的本地模塊cart.js也能夠換成JQuery等現成的模塊。

若是想對AMD有一個更深的瞭解,或者想知道如何定義一個AMD模塊。能夠先移步RequireJS官網。

CommonJS

JS有一條定律:Atwood's Law

any application that can be written in JavaScript, will eventually be written in JavaScript.

JS是能夠在服務端存在,因此出現了CommonJS(A Module Format Optimized For The Server),使得JS不只僅在瀏覽器端應用,並且在服務端開始發光發熱

CommonJS是專一於

  1. 服務端應用
  2. 公共工具方法
  3. 基於GUI的桌面程序
  4. 混合應用 (Titanium, Adobe AIR)

AMD不是一個服務層面。

Talk is cheap ,show you the code

a.js

var x = 5;
var addX = function (value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
複製代碼

上面代碼經過module.exports輸出變量x和函數addX。

b.js

var example = require('./a.js');
 
console.log(example.x); // 5
console.log(example.addX(1)); // 6
複製代碼

commonJS模塊特色

  1. 每一個文件就是一個模塊,它有本身的做用域(不會污染全局做用域)。在文件裏面定義的變量、函數、類,都是這個模塊的私有的,對外不可見。
  2. 模塊加載順序,按照代碼執行順序。也就是說,是同步加載的。
  3. 模塊能夠重複加載,可是會在加載第一次的時候,就將該模塊緩存起來,後面再次加載將從緩存中獲取該模塊。(注意:若是要從新加載模塊,須要清空緩存)

ES6 module

在ES6中,從語法層面就提供了模塊化的功能。然而受限於瀏覽器的實現程度,若是想要在瀏覽器中運行,仍是須要經過Babel等轉譯工具進行編譯。

person-module.js

var firstName = '北宸';
var lastName = '範';
export { firstName, lastName };
複製代碼

test-module.js

import {firstName,lastName} from './person-module.js';
console.log(`${lastName}${firstName}`)//範北宸
複製代碼

具體細節請參考Module的用法

各個模塊比較

模塊化方案 加載 同步/異步 瀏覽器 服務端 模塊定義 模塊引入
Module Pattern 取決於代碼 取決於代碼 支持 支持 IIFE 命名空間
AMD 提早預加載 異步 支持 構建工具r.js define require
Common 值拷貝,運行時加載 同步 原生不支持 須要使用browserify提早打包編譯 module.exports require
ES Modules(ES6) 實時綁定,動態綁定,編譯時輸出 同步 支持 需用babel轉譯 export import

本文參考連接:

  1. requirejs.org/docs/api.ht…
  2. addyosmani.com/resources/e…
  3. es6.ruanyifeng.com/#docs/modul…
  4. www.commonjs.org/
  5. www.cnblogs.com/scq000/p/10…
相關文章
相關標籤/搜索