模块化用来分割,组织和打包软件。每一个模块完成一个特定的子功能,全部的模块按某种方法组装起来,成为一个总体,完成整个系统所要求的功能。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解析才能使用