模塊化用來分割,組織和打包軟件。每一個模塊完成一個特定的子功能,全部的模塊按某種方法組裝起來,成爲一個總體,完成整個系統所要求的功能。html
- 命名空間衝突,多個庫可能會使用同一名稱
- 沒法合理的管理項目的依賴和版本
- 沒法方便的控制依賴的加載順序
## 現在前端模塊化的主流方式
利用自動化構建工具Gulp/Webpack 把源代碼轉換成發佈線上的可執行JavaScrip、CSS、HTML 代碼
一般自動化構建工具作的內容有:前端
## 模塊化的幾種規範node
## CommonJS
CommonJS定義的模塊分爲:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}
require()用來引入外部模塊;exports對象用於導出當前模塊的方法或變量,惟一的導出口;module對象就表明模塊自己。瀏覽器
// foo.js module.exports = function(x) { // 導出 console.log(x); }; // main.js var foo = require("./foo"); // 導入 foo("Hi");
瀏覽器不兼容CommonJS的根本緣由,在於缺乏四個Node.js環境的變量。安全
換言之, 只要咱們提供了這幾個, 瀏覽器就能加載 CommonJS 模塊。下面是一個簡單的示例服務器
var module = { exports: {} }; (function(module, exports) { exports.multiply = function (n) { return n * 1000 }; }(module, module.exports)) var f = module.exports.multiply; f(5) // 5000
function require(p){ var path = require.resolve(p); // 返回路徑 var mod = require.modules[path]; // 是否已註冊 if (!mod) throw new Error('failed to require "' + p + '"'); // 未註冊拋出 if (!mod.exports) { // 若是註冊了 就執行模塊 mod.exports = {}; mod.call(mod.exports, mod, mod.exports, require.relative(path)); // 執行模塊 } return mod.exports; } require.modules = {}; require.resolve = function (path){ var orig = path; var reg = path + '.js'; var index = path + '/index.js'; return require.modules[reg] && reg || require.modules[index] && index || orig; }; require.register = function (path, fn){ // 註冊模塊 require.modules[path] = fn; }; require.relative = function (parent) { return function(p){ if ('.' != p.charAt(0)) return require(p); var path = parent.split('/'); var segs = p.split('/'); path.pop(); for (var i = 0; i < segs.length; i++) { var seg = segs[i]; if ('..' == seg) path.pop(); else if ('.' != seg) path.push(seg); } return require(path.join('/')); }; }; require.register("moduleId", function(module, exports, require){ // 代碼寫在這裏 }); var result = require("moduleId");
優勢babel
- 可在不轉換代碼的狀況下直接在瀏覽器中運行
- 可加載多個依賴
- 代碼可運行在瀏覽器環境和 Node.js 環境下
缺點app
- JavaScript 運行環境沒有原生支持 AMD,須要先導入實現了 AMD 的庫後才能正常使用
define([module-name?], // 模塊名 [array-of-dependencies?], // 依賴模塊 [module-factory-or-object]); // 模塊的實現,或者一個JavaScript對象
define('a', [], function () { return 'a'; }); define('b', ['a'], function (a) { return a + 'b'; }); // 導入和使用 require(['b'], function (b) { console.log(b); });
define函數具備異步性。當define函數執行時,首先會異步的去調用第二個參數中列出的依賴模塊,當全部的模塊被載入完成以後,
若是第三個參數是一個回調函數則執行;而後告訴系統模塊可用,也就通知了依賴於本身的模塊本身已經可用異步
let factories = {}; function define(modName, dependencies, factory) { factory.dependencies = dependencies; // 依賴 factories[modName] = factory; // 儲存模塊 } function require(modNames, callback) { let loadedModNames = modNames.map(function (modName) { let factory = factories[modName]; let dependencies = factory.dependencies; let exports; require(dependencies, function (...dependencyMods) { exports = factory.apply(null, dependencyMods); }); return exports; }) callback.apply(null, loadedModNames); }
目前AMD使用比較少了ide
ES6 模塊化是ECMA提出的JavaScript模塊化規範,它在語言的層面上實現了模塊化。瀏覽器廠商和Node.js
都宣佈要原生支持該規範。它將逐漸取代CommonJS和AMD`規範,成爲瀏覽器和服務器通用的模塊解決方案。
優勢
- 主流方案, 各類瀏覽器廠商和node都逐漸支持
缺點
- 目前沒法直接運行在大部分 JavaScript 運行環境下,必須經過工具轉換成標準的 ES5 後才能正常運行
特色
- 若是你經過本地加載Html 文件 (好比一個 file:// 路徑的文件), 你將會遇到 CORS 錯誤,由於Javascript 模塊安全性須要。你須要經過一個服務器來測試。
- 自動使用嚴格模式。
- 加載一個模塊腳本時不須要使用 defer 屬性, 模塊會自動延遲加載。
- 沒法在全局得到. 所以,你只能在導入這些功能的腳本文件中使用他們,你也沒法經過Javascript console 中獲取到他們
- 基本使用
// 導出 export const name = 'xiaoming'; // 導入 import { name } from './person.js';
- 默認導出
// 導出 const name = 'xiaoming'; export default name // 導入 import name from './person.js'; // 或者 import {default as name} from './person.js';
- 重命名導出與導入
export { function1 as newFunctionName, function2 as anotherNewFunctionName }; // inside main.mjs import { newFunctionName, anotherNewFunctionName } from '/modules';
- 所有導入
import * as Module from '/modules/module'; Module.function1() Module.function2()
- 動態導入
import('/modules/myModule.mjs') .then((module) => { // Do something with the module. }); // 須要babel解析才能使用